Improve chunk block getter

Signed-off-by: TheMode <themode@outlook.fr>
This commit is contained in:
TheMode 2021-09-18 15:59:20 +02:00
parent 5376b8af76
commit dda90a6dfe
3 changed files with 49 additions and 76 deletions

View File

@ -1,11 +1,11 @@
package net.minestom.server.instance.palette;
import it.unimi.dsi.fastutil.shorts.Short2ShortLinkedOpenHashMap;
import it.unimi.dsi.fastutil.shorts.Short2ShortOpenHashMap;
import net.minestom.server.MinecraftServer;
import net.minestom.server.instance.Chunk;
import net.minestom.server.utils.MathUtils;
import net.minestom.server.utils.clone.PublicCloneable;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
import static net.minestom.server.instance.Chunk.CHUNK_SECTION_SIZE;
@ -15,6 +15,7 @@ import static net.minestom.server.instance.Chunk.CHUNK_SECTION_SIZE;
* <p>
* 0 is always interpreted as being air, reason being that the block array will be filled with it during initialization.
*/
@ApiStatus.Internal
public final class Palette implements PublicCloneable<Palette> {
/**
@ -44,11 +45,17 @@ public final class Palette implements PublicCloneable<Palette> {
511, 1023, 2047, 4095,
8191, 16383, 32767};
private static final Short2ShortOpenHashMap MAP_TEMPLATE = new Short2ShortOpenHashMap(CHUNK_SECTION_SIZE);
static {
MAP_TEMPLATE.put((short) 0, (short) 0);
}
private long[] blocks;
// chunk section - palette index = block id
private Short2ShortLinkedOpenHashMap paletteBlockMap;
// chunk section - block id = palette index
// palette index = block id
private short[] paletteBlockArray;
// block id = palette index
private Short2ShortOpenHashMap blockPaletteMap;
private int bitsPerEntry;
@ -56,6 +63,7 @@ public final class Palette implements PublicCloneable<Palette> {
private int valuesPerLong;
private boolean hasPalette;
private int lastPaletteIndex;
private short blockCount = 0;
@ -77,7 +85,7 @@ public final class Palette implements PublicCloneable<Palette> {
return;
}
// Initialize the section
blocks = new long[getSize(valuesPerLong)];
this.blocks = new long[(BLOCK_COUNT + valuesPerLong - 1) / valuesPerLong];
}
// Change to palette value
@ -121,10 +129,9 @@ public final class Palette implements PublicCloneable<Palette> {
final int index = sectionIdentifier / valuesPerLong;
final int bitIndex = sectionIdentifier % valuesPerLong * bitsPerEntry;
final long value = blocks[index] >> bitIndex & MAGIC_MASKS[bitsPerEntry];
final short value = (short) (blocks[index] >> bitIndex & MAGIC_MASKS[bitsPerEntry]);
// Change to palette value and return
return fromPalette((short) value);
return hasPalette ? paletteBlockArray[value] : value;
}
/**
@ -138,18 +145,21 @@ public final class Palette implements PublicCloneable<Palette> {
newBitsPerEntry = fixBitsPerEntry(newBitsPerEntry);
Palette palette = new Palette(newBitsPerEntry, bitsIncrement);
palette.paletteBlockMap = paletteBlockMap;
palette.paletteBlockArray = paletteBlockArray;
palette.blockPaletteMap = blockPaletteMap;
palette.lastPaletteIndex = lastPaletteIndex;
for (int y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) {
for (int x = 0; x < Chunk.CHUNK_SIZE_X; x++) {
for (int z = 0; z < Chunk.CHUNK_SIZE_Z; z++) {
final short blockId = getBlockAt(x, y, z);
palette.setBlockAt(x, y, z, blockId);
palette.setBlockAt(x, y, z, getBlockAt(x, y, z));
}
}
}
this.paletteBlockArray = palette.paletteBlockArray;
this.lastPaletteIndex = palette.lastPaletteIndex;
this.bitsPerEntry = palette.bitsPerEntry;
this.valuesPerLong = palette.valuesPerLong;
@ -177,15 +187,15 @@ public final class Palette implements PublicCloneable<Palette> {
if (canClear) {
this.blocks = new long[0];
}
}
}
public void clear() {
this.blocks = new long[0];
this.paletteBlockMap = createPaletteBlockMap();
this.blockPaletteMap = createBlockPaletteMap();
this.paletteBlockArray = new short[1 << bitsPerEntry];
this.blockPaletteMap = MAP_TEMPLATE.clone();
this.blockCount = 0;
this.lastPaletteIndex = 1; // First index is air
}
public long[] getBlocks() {
@ -197,7 +207,7 @@ public final class Palette implements PublicCloneable<Palette> {
}
/**
* Get the amount of non air blocks in this section.
* Get the amount of non-air blocks in this section.
*
* @return The amount of blocks in this section.
*/
@ -209,8 +219,12 @@ public final class Palette implements PublicCloneable<Palette> {
this.blockCount = blockCount;
}
public Short2ShortLinkedOpenHashMap getPaletteBlockMap() {
return paletteBlockMap;
public short[] getPaletteBlockArray() {
return paletteBlockArray;
}
public int getLastPaletteIndex() {
return lastPaletteIndex;
}
public Short2ShortOpenHashMap getBlockPaletteMap() {
@ -230,48 +244,18 @@ public final class Palette implements PublicCloneable<Palette> {
* @return the palette index of {@code blockId}
*/
private short getPaletteIndex(short blockId) {
if (!hasPalette) {
return blockId;
}
if (!hasPalette) return blockId;
final short value = blockPaletteMap.getOrDefault(blockId, (short) -1);
if (value == -1) {
// Resize the palette if full
if (paletteBlockMap.size() >= getMaxPaletteSize()) {
resize(bitsPerEntry + bitsIncrement);
}
final short paletteIndex = (short) (paletteBlockMap.lastShortKey() + 1);
paletteBlockMap.put(paletteIndex, blockId);
blockPaletteMap.put(blockId, paletteIndex);
return paletteIndex;
if (value != -1) return value;
if (lastPaletteIndex >= paletteBlockArray.length) {
// Palette is full, must resize
resize(bitsPerEntry + bitsIncrement);
}
return value;
}
/**
* Gets the maximum number of blocks that the current palette (could be the global one) can take.
*
* @return the number of blocks possible in the palette
*/
private int getMaxPaletteSize() {
return 1 << bitsPerEntry;
}
private short fromPalette(short value) {
return hasPalette ? paletteBlockMap.get(value) : value;
}
private static Short2ShortLinkedOpenHashMap createPaletteBlockMap() {
Short2ShortLinkedOpenHashMap map = new Short2ShortLinkedOpenHashMap(CHUNK_SECTION_SIZE);
map.put((short) 0, (short) 0);
return map;
}
private static Short2ShortOpenHashMap createBlockPaletteMap() {
Short2ShortOpenHashMap map = new Short2ShortOpenHashMap(CHUNK_SECTION_SIZE);
map.put((short) 0, (short) 0);
return map;
final short paletteIndex = (short) lastPaletteIndex++;
this.paletteBlockArray[paletteIndex] = blockId;
this.blockPaletteMap.put(blockId, paletteIndex);
return paletteIndex;
}
/**
@ -287,16 +271,6 @@ public final class Palette implements PublicCloneable<Palette> {
return y << 8 | z << 4 | x;
}
/**
* Gets the array length of one section based on the number of values which can be stored in one long.
*
* @param valuesPerLong the number of values per long
* @return the array length based on {@code valuesPerLong}
*/
private static int getSize(int valuesPerLong) {
return (BLOCK_COUNT + valuesPerLong - 1) / valuesPerLong;
}
/**
* Fixes invalid bitsPerEntry values.
* <p>
@ -314,13 +288,12 @@ public final class Palette implements PublicCloneable<Palette> {
return bitsPerEntry;
}
@NotNull
@Override
public Palette clone() {
public @NotNull Palette clone() {
try {
Palette palette = (Palette) super.clone();
palette.blocks = blocks.clone();
palette.paletteBlockMap = paletteBlockMap.clone();
palette.paletteBlockArray = paletteBlockArray.clone();
palette.blockPaletteMap = blockPaletteMap.clone();
palette.blockCount = blockCount;
return palette;

View File

@ -186,7 +186,7 @@ public class ChunkDataPacket implements ServerPacket {
int paletteSize = reader.readVarInt();
for (int i = 0; i < paletteSize; i++) {
final int paletteValue = reader.readVarInt();
palette.getPaletteBlockMap().put((short) i, (short) paletteValue);
palette.getPaletteBlockArray()[i] = (short) paletteValue;
palette.getBlockPaletteMap().put((short) paletteValue, (short) i);
}
}

View File

@ -1,6 +1,5 @@
package net.minestom.server.utils;
import it.unimi.dsi.fastutil.shorts.Short2ShortLinkedOpenHashMap;
import net.minestom.server.instance.palette.Palette;
import org.jetbrains.annotations.ApiStatus;
import org.jetbrains.annotations.NotNull;
@ -122,10 +121,11 @@ public final class Utils {
// Palette
if (bitsPerEntry < 9) {
// Palette has to exist
final Short2ShortLinkedOpenHashMap paletteBlockMap = palette.getPaletteBlockMap();
writeVarInt(buffer, paletteBlockMap.size());
for (short paletteValue : paletteBlockMap.values()) {
writeVarInt(buffer, paletteValue);
final short[] paletteBlockArray = palette.getPaletteBlockArray();
final int paletteSize = palette.getLastPaletteIndex() + 1;
writeVarInt(buffer, paletteSize);
for (int i = 0; i < paletteSize; i++) {
writeVarInt(buffer, paletteBlockArray[i]);
}
}