Custom blocks also use a PaletteStorage object, removed StaticChunk since memory is not an issue anymore

This commit is contained in:
themode 2020-11-11 07:29:07 +01:00
parent 4dfe01ea2f
commit 93bae25085
6 changed files with 26 additions and 159 deletions

View File

@ -12,7 +12,6 @@ import net.minestom.server.entity.pathfinding.PFBlockDescription;
import net.minestom.server.instance.block.CustomBlock; import net.minestom.server.instance.block.CustomBlock;
import net.minestom.server.instance.palette.PaletteStorage; import net.minestom.server.instance.palette.PaletteStorage;
import net.minestom.server.network.packet.server.play.ChunkDataPacket; import net.minestom.server.network.packet.server.play.ChunkDataPacket;
import net.minestom.server.utils.ArrayUtils;
import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.BlockPosition;
import net.minestom.server.utils.binary.BinaryReader; import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.binary.BinaryWriter; import net.minestom.server.utils.binary.BinaryWriter;
@ -42,12 +41,9 @@ public class DynamicChunk extends Chunk {
*/ */
private static final int DATA_FORMAT_VERSION = 1; private static final int DATA_FORMAT_VERSION = 1;
// blocks id based on coordinate, see Chunk#getBlockIndex // WARNING: not thread-safe
// 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 PaletteStorage blockPalette = new PaletteStorage(15);
protected final short[] customBlocksId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z]; protected PaletteStorage customBlockPalette = new PaletteStorage(15);
// Used to get all blocks with data (no null) // Used to get all blocks with data (no null)
// Key is still chunk coordinates (see #getBlockIndex) // Key is still chunk coordinates (see #getBlockIndex)
@ -82,13 +78,13 @@ public class DynamicChunk extends Chunk {
final boolean hasBlock = blockStateId != 0 || customBlockId != 0; final boolean hasBlock = blockStateId != 0 || customBlockId != 0;
if (hasBlock) { if (hasBlock) {
this.blockPalette.setBlockAt(x, y, z, blockStateId); this.blockPalette.setBlockAt(x, y, z, blockStateId);
this.customBlocksId[index] = customBlockId; this.customBlockPalette.setBlockAt(x, y, z, customBlockId);
} else { } else {
// Block has been deleted, clear cache and return // Block has been deleted, clear cache and return
this.blockPalette.setBlockAt(x, y, z, (short) 0); this.blockPalette.setBlockAt(x, y, z, (short) 0);
//this.blocksStateId[index] = 0; // Set to air //this.blocksStateId[index] = 0; // Set to air
this.customBlocksId[index] = 0; // Remove custom block this.customBlockPalette.setBlockAt(x, y, z, (short) 0); // Remove custom block
this.blocksData.remove(index); this.blocksData.remove(index);
@ -158,15 +154,13 @@ public class DynamicChunk extends Chunk {
@Override @Override
public short getCustomBlockId(int x, int y, int z) { public short getCustomBlockId(int x, int y, int z) {
final int index = getBlockIndex(x, y, z); return customBlockPalette.getBlockAt(x, y, z);
return customBlocksId[index];
} }
@Override @Override
protected void refreshBlockValue(int x, int y, int z, short blockStateId, short customBlockId) { protected void refreshBlockValue(int x, int y, int z, short blockStateId, short customBlockId) {
final int blockIndex = getBlockIndex(x, y, z);
this.blockPalette.setBlockAt(x, y, z, blockStateId); this.blockPalette.setBlockAt(x, y, z, blockStateId);
this.customBlocksId[blockIndex] = customBlockId; this.customBlockPalette.setBlockAt(x, y, z, customBlockId);
} }
@Override @Override
@ -243,7 +237,7 @@ public class DynamicChunk extends Chunk {
final int index = getBlockIndex(x, y, z); final int index = getBlockIndex(x, y, z);
final short blockStateId = blockPalette.getBlockAt(x, y, z); final short blockStateId = blockPalette.getBlockAt(x, y, z);
final short customBlockId = customBlocksId[index]; final short customBlockId = customBlockPalette.getBlockAt(x, y, z);
// No block at the position // No block at the position
if (blockStateId == 0 && customBlockId == 0) if (blockStateId == 0 && customBlockId == 0)
@ -381,7 +375,7 @@ public class DynamicChunk extends Chunk {
fullDataPacket.chunkX = chunkX; fullDataPacket.chunkX = chunkX;
fullDataPacket.chunkZ = chunkZ; fullDataPacket.chunkZ = chunkZ;
fullDataPacket.paletteStorage = blockPalette.copy(); fullDataPacket.paletteStorage = blockPalette.copy();
fullDataPacket.customBlocksId = customBlocksId.clone(); fullDataPacket.customBlockPaletteStorage = customBlockPalette.copy();
fullDataPacket.blockEntities = new HashSet<>(blockEntities); fullDataPacket.blockEntities = new HashSet<>(blockEntities);
fullDataPacket.blocksData = new Int2ObjectOpenHashMap<>(blocksData); fullDataPacket.blocksData = new Int2ObjectOpenHashMap<>(blocksData);
return fullDataPacket; return fullDataPacket;
@ -392,7 +386,7 @@ public class DynamicChunk extends Chunk {
public Chunk copy(int chunkX, int chunkZ) { public Chunk copy(int chunkX, int chunkZ) {
DynamicChunk dynamicChunk = new DynamicChunk(biomes.clone(), chunkX, chunkZ); DynamicChunk dynamicChunk = new DynamicChunk(biomes.clone(), chunkX, chunkZ);
dynamicChunk.blockPalette = blockPalette.copy(); dynamicChunk.blockPalette = blockPalette.copy();
ArrayUtils.copyToDestination(customBlocksId, dynamicChunk.customBlocksId); dynamicChunk.customBlockPalette = customBlockPalette.copy();
dynamicChunk.blocksData.putAll(blocksData); dynamicChunk.blocksData.putAll(blocksData);
dynamicChunk.updatableBlocks.addAll(updatableBlocks); dynamicChunk.updatableBlocks.addAll(updatableBlocks);
dynamicChunk.updatableBlocksLastUpdate.putAll(updatableBlocksLastUpdate); dynamicChunk.updatableBlocksLastUpdate.putAll(updatableBlocksLastUpdate);

View File

@ -581,7 +581,7 @@ public class InstanceContainer extends Instance {
* @throws NullPointerException if {@code chunkSupplier} is null * @throws NullPointerException if {@code chunkSupplier} is null
*/ */
public void setChunkSupplier(@NotNull ChunkSupplier chunkSupplier) { public void setChunkSupplier(@NotNull ChunkSupplier chunkSupplier) {
Check.notNull(chunkSupplier, "The chunk supplier cannot be null, you can use a StaticChunk for a lightweight implementation"); Check.notNull(chunkSupplier, "The chunk supplier cannot be null!");
this.chunkSupplier = chunkSupplier; this.chunkSupplier = chunkSupplier;
} }

View File

@ -1,127 +0,0 @@
package net.minestom.server.instance;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import net.minestom.server.data.Data;
import net.minestom.server.instance.block.BlockProvider;
import net.minestom.server.network.packet.server.play.ChunkDataPacket;
import net.minestom.server.utils.binary.BinaryReader;
import net.minestom.server.utils.callback.OptionalCallback;
import net.minestom.server.utils.chunk.ChunkCallback;
import net.minestom.server.utils.chunk.ChunkUtils;
import net.minestom.server.world.biomes.Biome;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashSet;
import java.util.Set;
/**
* Represents a {@link Chunk} which does not store any block, it makes use of a {@link BlockProvider}
* instead to use less memory.
* <p>
* Can be used for very simple chunks such as flat or others with not any random factor.
* <p>
* WARNING: adding blocks or anything to this chunk would not work, it is static.
*/
public class StaticChunk extends Chunk {
protected final BlockProvider blockProvider;
public StaticChunk(@Nullable Biome[] biomes, int chunkX, int chunkZ,
@NotNull BlockProvider blockProvider) {
super(biomes, chunkX, chunkZ, false);
this.blockProvider = blockProvider;
setReadOnly(true);
}
@Override
public void UNSAFE_setBlock(int x, int y, int z, short blockStateId, short customBlockId, @Nullable Data data, boolean updatable) {
//noop
}
@Override
public void tick(long time, @NotNull Instance instance) {
//noop
}
@Override
public short getBlockStateId(int x, int y, int z) {
return blockProvider.getBlockStateId(x, y, z);
}
@Override
public short getCustomBlockId(int x, int y, int z) {
//noop
return 0;
}
@Override
protected void refreshBlockValue(int x, int y, int z, short blockStateId, short customId) {
//noop
}
@Override
protected void refreshBlockStateId(int x, int y, int z, short blockStateId) {
//noop
}
@Override
public Data getBlockData(int index) {
return null;
}
@Override
public void setBlockData(int x, int y, int z, Data data) {
//noop
}
@NotNull
@Override
public Set<Integer> getBlockEntities() {
return new HashSet<>();
}
@Override
public byte[] getSerializedData() {
return null;
}
@Override
public void readChunk(@NotNull BinaryReader reader, @Nullable ChunkCallback callback) {
OptionalCallback.execute(callback, this);
}
@NotNull
@Override
protected ChunkDataPacket createFreshPacket() {
ChunkDataPacket fullDataPacket = new ChunkDataPacket();
fullDataPacket.biomes = biomes.clone();
fullDataPacket.chunkX = chunkX;
fullDataPacket.chunkZ = chunkZ;
short[] blocksStateId = new short[CHUNK_SIZE_X * CHUNK_SIZE_Y * CHUNK_SIZE_Z];
for (int i = 0; i < blocksStateId.length; i++) {
final int x = ChunkUtils.blockIndexToChunkPositionX(i);
final int y = ChunkUtils.blockIndexToChunkPositionY(i);
final int z = ChunkUtils.blockIndexToChunkPositionZ(i);
blocksStateId[i] = blockProvider.getBlockStateId(x, y, z);
}
//fullDataPacket.blocksStateId = blocksStateId;
fullDataPacket.customBlocksId = new short[0];
fullDataPacket.blockEntities = new HashSet<>();
fullDataPacket.blocksData = new Int2ObjectOpenHashMap<>();
return fullDataPacket;
}
@NotNull
@Override
public Chunk copy(int chunkX, int chunkZ) {
StaticChunk staticChunk = new StaticChunk(biomes.clone(), chunkX, chunkZ, blockProvider);
// Prevent re-writing the whole packet since it is static anyway
/*final ByteBuf packetBuffer = getFullDataPacket();
if (packetBuffer != null) {
staticChunk.setFullDataPacket(packetBuffer);
}*/
return staticChunk;
}
}

View File

@ -1,6 +0,0 @@
package net.minestom.server.instance.block;
@FunctionalInterface
public interface BlockProvider {
short getBlockStateId(int x, int y, int z);
}

View File

@ -33,6 +33,10 @@ public class PaletteStorage {
final int section = y / CHUNK_SECTION_SIZE; final int section = y / CHUNK_SECTION_SIZE;
if (sectionBlocks[section].length == 0) { if (sectionBlocks[section].length == 0) {
if (blockId == 0) {
return;
}
sectionBlocks[section] = new long[getSize()]; sectionBlocks[section] = new long[getSize()];
} }
@ -95,18 +99,18 @@ public class PaletteStorage {
long finalValue; long finalValue;
System.out.println("index " + index); /*System.out.println("index " + index);
System.out.println("bitIndex " + bitIndex); System.out.println("bitIndex " + bitIndex);
System.out.println("test1 " + binary(value)); System.out.println("test1 " + binary(value));
System.out.println("test2 " + binary(mask)); System.out.println("test2 " + binary(mask));*/
{ {
mask = mask >> bitIndex << bitIndex; mask = mask >> bitIndex << bitIndex;
System.out.println("test3 " + binary(mask)); //System.out.println("test3 " + binary(mask));
finalValue = value & mask >> bitIndex; finalValue = value & mask >> bitIndex;
} }
System.out.println("final " + binary(finalValue)); //System.out.println("final " + binary(finalValue));
/*System.out.println("data " + index + " " + bitIndex + " " + sectionIndex); /*System.out.println("data " + index + " " + bitIndex + " " + sectionIndex);

View File

@ -29,7 +29,7 @@ public class ChunkDataPacket implements ServerPacket {
public int chunkX, chunkZ; public int chunkX, chunkZ;
public PaletteStorage paletteStorage; public PaletteStorage paletteStorage;
public short[] customBlocksId; public PaletteStorage customBlockPaletteStorage;
public Set<Integer> blockEntities; public Set<Integer> blockEntities;
public Int2ObjectMap<Data> blocksData; public Int2ObjectMap<Data> blocksData;
@ -106,12 +106,14 @@ public class ChunkDataPacket implements ServerPacket {
.setInt("y", blockPosition.getY()) .setInt("y", blockPosition.getY())
.setInt("z", blockPosition.getZ()); .setInt("z", blockPosition.getZ());
final short customBlockId = customBlocksId[index]; if (customBlockPaletteStorage != null) {
final short customBlockId = customBlockPaletteStorage.getBlockAt(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ());
final CustomBlock customBlock = BLOCK_MANAGER.getCustomBlock(customBlockId); final CustomBlock customBlock = BLOCK_MANAGER.getCustomBlock(customBlockId);
if (customBlock != null) { if (customBlock != null) {
final Data data = blocksData.get(index); final Data data = blocksData.get(index);
customBlock.writeBlockEntity(blockPosition, data, nbt); customBlock.writeBlockEntity(blockPosition, data, nbt);
} }
}
writer.writeNBT("", nbt); writer.writeNBT("", nbt);
} }
} }