mirror of
https://github.com/Minestom/Minestom.git
synced 2024-12-28 12:07:42 +01:00
WIP PaletteStorage (only works with Bits per entry of 15)
This commit is contained in:
parent
b6bf6a17ba
commit
4dfe01ea2f
@ -10,6 +10,7 @@ import net.minestom.server.data.SerializableData;
|
||||
import net.minestom.server.data.SerializableDataImpl;
|
||||
import net.minestom.server.entity.pathfinding.PFBlockDescription;
|
||||
import net.minestom.server.instance.block.CustomBlock;
|
||||
import net.minestom.server.instance.palette.PaletteStorage;
|
||||
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
|
||||
import net.minestom.server.utils.ArrayUtils;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
@ -35,8 +36,6 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
||||
*/
|
||||
public class DynamicChunk extends Chunk {
|
||||
|
||||
private static final int BITS_PER_ENTRY = 15;
|
||||
|
||||
/**
|
||||
* Represents the version which will be present in the serialized output.
|
||||
* Used to define which deserializer to use.
|
||||
@ -47,10 +46,9 @@ public class DynamicChunk extends Chunk {
|
||||
// WARNING: those arrays are NOT thread-safe
|
||||
// and modifying them can cause issue with block data, update, block entity and the cached chunk packet
|
||||
//protected final short[] blocksStateId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
|
||||
protected PaletteStorage blockPalette = new PaletteStorage(15);
|
||||
protected final short[] customBlocksId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
|
||||
|
||||
protected long[][] sectionBlocks = new long[CHUNK_SECTION_COUNT][0];
|
||||
|
||||
// Used to get all blocks with data (no null)
|
||||
// Key is still chunk coordinates (see #getBlockIndex)
|
||||
protected final Int2ObjectMap<Data> blocksData = new Int2ObjectOpenHashMap<>();
|
||||
@ -63,8 +61,8 @@ public class DynamicChunk extends Chunk {
|
||||
// Block entities
|
||||
protected final Set<Integer> blockEntities = new CopyOnWriteArraySet<>();
|
||||
|
||||
public DynamicChunk(@NotNull Instance instance, @Nullable Biome[] biomes, int chunkX, int chunkZ) {
|
||||
super(instance, biomes, chunkX, chunkZ, true);
|
||||
public DynamicChunk(@Nullable Biome[] biomes, int chunkX, int chunkZ) {
|
||||
super(biomes, chunkX, chunkZ, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -83,12 +81,12 @@ public class DynamicChunk extends Chunk {
|
||||
// True if the block is not complete air without any custom block capabilities
|
||||
final boolean hasBlock = blockStateId != 0 || customBlockId != 0;
|
||||
if (hasBlock) {
|
||||
setBlockAt(x, y, z, blockStateId);
|
||||
this.blockPalette.setBlockAt(x, y, z, blockStateId);
|
||||
this.customBlocksId[index] = customBlockId;
|
||||
} else {
|
||||
// Block has been deleted, clear cache and return
|
||||
|
||||
setBlockAt(x, y, z, (short) 0);
|
||||
this.blockPalette.setBlockAt(x, y, z, (short) 0);
|
||||
//this.blocksStateId[index] = 0; // Set to air
|
||||
this.customBlocksId[index] = 0; // Remove custom block
|
||||
|
||||
@ -155,8 +153,7 @@ public class DynamicChunk extends Chunk {
|
||||
|
||||
@Override
|
||||
public short getBlockStateId(int x, int y, int z) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
return getBlockAt(x, y, z);
|
||||
return this.blockPalette.getBlockAt(x, y, z);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -168,14 +165,13 @@ public class DynamicChunk extends Chunk {
|
||||
@Override
|
||||
protected void refreshBlockValue(int x, int y, int z, short blockStateId, short customBlockId) {
|
||||
final int blockIndex = getBlockIndex(x, y, z);
|
||||
setBlockAt(x, y, z, blockStateId);
|
||||
this.blockPalette.setBlockAt(x, y, z, blockStateId);
|
||||
this.customBlocksId[blockIndex] = customBlockId;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void refreshBlockStateId(int x, int y, int z, short blockStateId) {
|
||||
final int blockIndex = getBlockIndex(x, y, z);
|
||||
setBlockAt(x, y, z, blockStateId);
|
||||
this.blockPalette.setBlockAt(x, y, z, blockStateId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -246,7 +242,7 @@ public class DynamicChunk extends Chunk {
|
||||
for (byte z = 0; z < CHUNK_SIZE_Z; z++) {
|
||||
final int index = getBlockIndex(x, y, z);
|
||||
|
||||
final short blockStateId = getBlockAt(x, y, z);
|
||||
final short blockStateId = blockPalette.getBlockAt(x, y, z);
|
||||
final short customBlockId = customBlocksId[index];
|
||||
|
||||
// No block at the position
|
||||
@ -384,8 +380,7 @@ public class DynamicChunk extends Chunk {
|
||||
fullDataPacket.biomes = biomes.clone();
|
||||
fullDataPacket.chunkX = chunkX;
|
||||
fullDataPacket.chunkZ = chunkZ;
|
||||
fullDataPacket.bitsPerEntry = BITS_PER_ENTRY;
|
||||
fullDataPacket.sectionBlocks = sectionBlocks.clone();
|
||||
fullDataPacket.paletteStorage = blockPalette.copy();
|
||||
fullDataPacket.customBlocksId = customBlocksId.clone();
|
||||
fullDataPacket.blockEntities = new HashSet<>(blockEntities);
|
||||
fullDataPacket.blocksData = new Int2ObjectOpenHashMap<>(blocksData);
|
||||
@ -394,9 +389,9 @@ public class DynamicChunk extends Chunk {
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Chunk copy(@NotNull Instance instance, int chunkX, int chunkZ) {
|
||||
DynamicChunk dynamicChunk = new DynamicChunk(instance, biomes.clone(), chunkX, chunkZ);
|
||||
dynamicChunk.sectionBlocks = sectionBlocks.clone();
|
||||
public Chunk copy(int chunkX, int chunkZ) {
|
||||
DynamicChunk dynamicChunk = new DynamicChunk(biomes.clone(), chunkX, chunkZ);
|
||||
dynamicChunk.blockPalette = blockPalette.copy();
|
||||
ArrayUtils.copyToDestination(customBlocksId, dynamicChunk.customBlocksId);
|
||||
dynamicChunk.blocksData.putAll(blocksData);
|
||||
dynamicChunk.updatableBlocks.addAll(updatableBlocks);
|
||||
@ -405,82 +400,4 @@ public class DynamicChunk extends Chunk {
|
||||
|
||||
return dynamicChunk;
|
||||
}
|
||||
|
||||
private void setBlockAt(int x, int y, int z, short blockId) {
|
||||
x %= 16;
|
||||
if (x < 0) {
|
||||
x = CHUNK_SIZE_X + x;
|
||||
}
|
||||
z %= 16;
|
||||
if (z < 0) {
|
||||
z = CHUNK_SIZE_Z + z;
|
||||
}
|
||||
|
||||
final char valuesPerLong = (char) (Long.SIZE / BITS_PER_ENTRY);
|
||||
|
||||
int sectionY = y % CHUNK_SECTION_SIZE;
|
||||
int sectionIndex = (((sectionY * 16) + z) * 16) + x;
|
||||
|
||||
final int index = sectionIndex / valuesPerLong;
|
||||
final int bitIndex = sectionIndex % valuesPerLong * BITS_PER_ENTRY;
|
||||
|
||||
final int section = y / CHUNK_SECTION_SIZE;
|
||||
|
||||
if (sectionBlocks[section].length == 0) {
|
||||
sectionBlocks[section] = new long[getSize()];
|
||||
}
|
||||
|
||||
long[] sectionBlock = sectionBlocks[section];
|
||||
|
||||
//System.out.println("test1 " + binary(sectionBlock[index]));
|
||||
//System.out.println("test2 " + binary(((long) blockId << (bitIndex))));
|
||||
sectionBlock[index] |= ((long) blockId << (bitIndex));
|
||||
}
|
||||
|
||||
private static String binary(long value) {
|
||||
return "0b" + Long.toBinaryString(value);
|
||||
}
|
||||
|
||||
private short getBlockAt(int x, int y, int z) {
|
||||
x %= 16;
|
||||
if (x < 0) {
|
||||
x = CHUNK_SIZE_X + x;
|
||||
}
|
||||
z %= 16;
|
||||
if (z < 0) {
|
||||
z = CHUNK_SIZE_Z + z;
|
||||
}
|
||||
|
||||
final char valuesPerLong = (char) (Long.SIZE / BITS_PER_ENTRY);
|
||||
|
||||
int sectionY = y % CHUNK_SECTION_SIZE;
|
||||
int sectionIndex = (((sectionY * 16) + z) * 16) + x;
|
||||
|
||||
final int index = sectionIndex / valuesPerLong;
|
||||
final int bitIndex = sectionIndex % valuesPerLong * BITS_PER_ENTRY;
|
||||
|
||||
final int section = y / CHUNK_SECTION_SIZE;
|
||||
|
||||
long[] blocks = sectionBlocks[section];
|
||||
|
||||
if (blocks.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
long mask = (1 << (bitIndex)) - 1;
|
||||
|
||||
/*System.out.println("data " + index + " " + bitIndex + " " + sectionIndex);
|
||||
System.out.println("POS " + x + " " + y + " " + z);
|
||||
System.out.println("mask " + binary(mask));
|
||||
System.out.println("bin " + binary(blocks[index]));
|
||||
System.out.println("result " + ((blocks[index] >> bitIndex) & mask));*/
|
||||
return (short) (blocks[index] >> bitIndex & mask);
|
||||
}
|
||||
|
||||
private int getSize() {
|
||||
final int blockCount = 16 * 16 * 16; // A whole chunk section
|
||||
final char valuesPerLong = (char) (Long.SIZE / BITS_PER_ENTRY);
|
||||
final int arraySize = blockCount / valuesPerLong;
|
||||
return arraySize;
|
||||
}
|
||||
}
|
@ -0,0 +1,146 @@
|
||||
package net.minestom.server.instance.palette;
|
||||
|
||||
import static net.minestom.server.instance.Chunk.*;
|
||||
|
||||
public class PaletteStorage {
|
||||
|
||||
private int bitsPerEntry;
|
||||
private int valuesPerLong;
|
||||
|
||||
protected long[][] sectionBlocks = new long[CHUNK_SECTION_COUNT][0];
|
||||
|
||||
public PaletteStorage(int bitsPerEntry) {
|
||||
this.bitsPerEntry = bitsPerEntry;
|
||||
this.valuesPerLong = Long.SIZE / bitsPerEntry;
|
||||
}
|
||||
|
||||
public void setBlockAt(int x, int y, int z, short blockId) {
|
||||
x %= 16;
|
||||
if (x < 0) {
|
||||
x = CHUNK_SIZE_X + x;
|
||||
}
|
||||
z %= 16;
|
||||
if (z < 0) {
|
||||
z = CHUNK_SIZE_Z + z;
|
||||
}
|
||||
|
||||
int sectionY = y % CHUNK_SECTION_SIZE;
|
||||
int sectionIndex = (((sectionY * 16) + z) * 16) + x;
|
||||
|
||||
final int index = sectionIndex / valuesPerLong;
|
||||
final int bitIndex = (sectionIndex % valuesPerLong) * bitsPerEntry;
|
||||
|
||||
final int section = y / CHUNK_SECTION_SIZE;
|
||||
|
||||
if (sectionBlocks[section].length == 0) {
|
||||
sectionBlocks[section] = new long[getSize()];
|
||||
}
|
||||
|
||||
long[] sectionBlock = sectionBlocks[section];
|
||||
|
||||
long block = sectionBlock[index];
|
||||
{
|
||||
if (blockId != 0) {
|
||||
long shiftCount = (long) bitIndex;
|
||||
long cacheMask = (1L << shiftCount) - 1L;
|
||||
long cache = block & cacheMask;
|
||||
|
||||
/*System.out.println("blockId "+blockId);
|
||||
System.out.println("bitIndex "+bitIndex);
|
||||
System.out.println("block "+binary(block));
|
||||
System.out.println("mask "+binary(cacheMask));
|
||||
System.out.println("cache "+binary(cache));*/
|
||||
|
||||
block = block >> shiftCount << shiftCount;
|
||||
//System.out.println("block "+binary(block));
|
||||
block = block | (long) blockId;
|
||||
//System.out.println("block2 "+binary(block));
|
||||
block = (block << shiftCount);
|
||||
//System.out.println("block3 "+binary(block));
|
||||
block = block | cache;
|
||||
//System.out.println("block4 "+binary(block));
|
||||
|
||||
sectionBlock[index] = block;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public short getBlockAt(int x, int y, int z) {
|
||||
x %= 16;
|
||||
if (x < 0) {
|
||||
x = CHUNK_SIZE_X + x;
|
||||
}
|
||||
z %= 16;
|
||||
if (z < 0) {
|
||||
z = CHUNK_SIZE_Z + z;
|
||||
}
|
||||
|
||||
int sectionY = y % CHUNK_SECTION_SIZE;
|
||||
int sectionIndex = (((sectionY * 16) + z) * 16) + x;
|
||||
|
||||
final int index = sectionIndex / valuesPerLong;
|
||||
final int bitIndex = sectionIndex % valuesPerLong * bitsPerEntry;
|
||||
|
||||
final int section = y / CHUNK_SECTION_SIZE;
|
||||
|
||||
long[] blocks = sectionBlocks[section];
|
||||
|
||||
if (blocks.length == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
long value = blocks[index] >> bitIndex;
|
||||
long mask = (1L << ((long) bitIndex + (long) bitsPerEntry)) - 1L;
|
||||
|
||||
long finalValue;
|
||||
|
||||
System.out.println("index " + index);
|
||||
System.out.println("bitIndex " + bitIndex);
|
||||
System.out.println("test1 " + binary(value));
|
||||
System.out.println("test2 " + binary(mask));
|
||||
|
||||
{
|
||||
mask = mask >> bitIndex << bitIndex;
|
||||
System.out.println("test3 " + binary(mask));
|
||||
finalValue = value & mask >> bitIndex;
|
||||
}
|
||||
|
||||
System.out.println("final " + binary(finalValue));
|
||||
|
||||
|
||||
/*System.out.println("data " + index + " " + bitIndex + " " + sectionIndex);
|
||||
System.out.println("POS " + x + " " + y + " " + z);
|
||||
System.out.println("mask " + binary(mask));
|
||||
System.out.println("bin " + binary(blocks[index]));
|
||||
System.out.println("result " + ((blocks[index] >> bitIndex) & mask));*/
|
||||
return (short) (finalValue);
|
||||
}
|
||||
|
||||
private int getSize() {
|
||||
final int blockCount = 16 * 16 * 16; // A whole chunk section
|
||||
final int arraySize = (blockCount + valuesPerLong - 1) / valuesPerLong;
|
||||
//System.out.println("size " + arraySize);
|
||||
return arraySize;
|
||||
}
|
||||
|
||||
public int getBitsPerEntry() {
|
||||
return bitsPerEntry;
|
||||
}
|
||||
|
||||
public long[][] getSectionBlocks() {
|
||||
return sectionBlocks;
|
||||
}
|
||||
|
||||
public PaletteStorage copy() {
|
||||
PaletteStorage paletteStorage = new PaletteStorage(bitsPerEntry);
|
||||
paletteStorage.sectionBlocks = sectionBlocks.clone();
|
||||
|
||||
return paletteStorage;
|
||||
}
|
||||
|
||||
private static String binary(long value) {
|
||||
return "0b" + Long.toBinaryString(value);
|
||||
}
|
||||
|
||||
}
|
@ -7,6 +7,7 @@ import net.minestom.server.MinecraftServer;
|
||||
import net.minestom.server.data.Data;
|
||||
import net.minestom.server.instance.block.BlockManager;
|
||||
import net.minestom.server.instance.block.CustomBlock;
|
||||
import net.minestom.server.instance.palette.PaletteStorage;
|
||||
import net.minestom.server.network.packet.server.ServerPacket;
|
||||
import net.minestom.server.network.packet.server.ServerPacketIdentifier;
|
||||
import net.minestom.server.utils.BlockPosition;
|
||||
@ -27,8 +28,7 @@ public class ChunkDataPacket implements ServerPacket {
|
||||
public Biome[] biomes;
|
||||
public int chunkX, chunkZ;
|
||||
|
||||
public int bitsPerEntry;
|
||||
public long[][] sectionBlocks;
|
||||
public PaletteStorage paletteStorage;
|
||||
public short[] customBlocksId;
|
||||
|
||||
public Set<Integer> blockEntities;
|
||||
@ -37,7 +37,7 @@ public class ChunkDataPacket implements ServerPacket {
|
||||
public int[] sections;
|
||||
|
||||
private static final byte CHUNK_SECTION_COUNT = 16;
|
||||
private static final int MAX_BITS_PER_ENTRY = 15;
|
||||
private static final int MAX_BITS_PER_ENTRY = 16;
|
||||
private static final int MAX_BUFFER_SIZE = (Short.BYTES + Byte.BYTES + 5 * Byte.BYTES + (4096 * MAX_BITS_PER_ENTRY / Long.SIZE * Long.BYTES)) * CHUNK_SECTION_COUNT + 256 * Integer.BYTES;
|
||||
|
||||
@Override
|
||||
@ -50,11 +50,11 @@ public class ChunkDataPacket implements ServerPacket {
|
||||
ByteBuf blocks = Unpooled.buffer(MAX_BUFFER_SIZE);
|
||||
for (byte i = 0; i < CHUNK_SECTION_COUNT; i++) {
|
||||
if (fullChunk || (sections.length == CHUNK_SECTION_COUNT && sections[i] != 0)) {
|
||||
final long[] section = sectionBlocks[i];
|
||||
final long[] section = paletteStorage.getSectionBlocks()[i];
|
||||
if (section.length > 0) { // section contains at least one block
|
||||
//if (true) {
|
||||
mask |= 1 << i;
|
||||
Utils.writeBlocks(blocks, section, bitsPerEntry);
|
||||
Utils.writeBlocks(blocks, section, paletteStorage.getBitsPerEntry());
|
||||
} else {
|
||||
mask |= 0;
|
||||
}
|
||||
|
@ -23,8 +23,6 @@ import net.minestom.server.item.ItemStack;
|
||||
import net.minestom.server.item.Material;
|
||||
import net.minestom.server.network.ConnectionManager;
|
||||
import net.minestom.server.ping.ResponseDataConsumer;
|
||||
import net.minestom.server.storage.StorageLocation;
|
||||
import net.minestom.server.storage.StorageOptions;
|
||||
import net.minestom.server.utils.Position;
|
||||
import net.minestom.server.utils.Vector;
|
||||
import net.minestom.server.utils.time.TimeUnit;
|
||||
@ -39,12 +37,12 @@ public class PlayerInit {
|
||||
private static final Inventory inventory;
|
||||
|
||||
static {
|
||||
StorageLocation storageLocation = MinecraftServer.getStorageManager().getLocation("instance_data", new StorageOptions().setCompression(true));
|
||||
//StorageLocation storageLocation = MinecraftServer.getStorageManager().getLocation("instance_data", new StorageOptions().setCompression(true));
|
||||
ChunkGeneratorDemo chunkGeneratorDemo = new ChunkGeneratorDemo();
|
||||
NoiseTestGenerator noiseTestGenerator = new NoiseTestGenerator();
|
||||
instanceContainer = MinecraftServer.getInstanceManager().createInstanceContainer(DimensionType.OVERWORLD, storageLocation);
|
||||
instanceContainer = MinecraftServer.getInstanceManager().createInstanceContainer(DimensionType.OVERWORLD);
|
||||
instanceContainer.enableAutoChunkLoad(true);
|
||||
instanceContainer.setChunkGenerator(noiseTestGenerator);
|
||||
instanceContainer.setChunkGenerator(chunkGeneratorDemo);
|
||||
|
||||
// Load some chunks beforehand
|
||||
final int loopStart = -3;
|
||||
@ -174,7 +172,7 @@ public class PlayerInit {
|
||||
|
||||
ItemStack itemStack = new ItemStack(Material.DIAMOND_PICKAXE, (byte) 64);
|
||||
NbtDataImpl data = new NbtDataImpl();
|
||||
data.set("testc",2);
|
||||
data.set("testc", 2);
|
||||
itemStack.setData(data);
|
||||
player.getInventory().addItemStack(itemStack);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user