From c363b715ca9080b18551bd6ad6cdef73840f3250 Mon Sep 17 00:00:00 2001 From: Felix Cravic Date: Wed, 27 May 2020 16:25:05 +0200 Subject: [PATCH] Optimize ChunkDataPacket, and having an universal block index method --- .../net/minestom/server/instance/Chunk.java | 55 ++++++++++--------- .../minestom/server/instance/Instance.java | 3 +- .../server/instance/InstanceContainer.java | 5 +- .../packet/server/play/ChunkDataPacket.java | 49 +++++++++++------ .../server/utils/SerializerUtils.java | 39 ------------- .../server/utils/chunk/ChunkUtils.java | 31 +++++++++++ .../server/utils/item/NbtReaderUtils.java | 2 +- 7 files changed, 97 insertions(+), 87 deletions(-) diff --git a/src/main/java/net/minestom/server/instance/Chunk.java b/src/main/java/net/minestom/server/instance/Chunk.java index 79b07792f..13b504014 100644 --- a/src/main/java/net/minestom/server/instance/Chunk.java +++ b/src/main/java/net/minestom/server/instance/Chunk.java @@ -18,7 +18,7 @@ import net.minestom.server.network.packet.server.play.ChunkDataPacket; import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.PacketUtils; -import net.minestom.server.utils.SerializerUtils; +import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.time.CooldownUtils; import net.minestom.server.utils.time.UpdateOption; import net.minestom.server.utils.validate.Check; @@ -91,8 +91,8 @@ public class Chunk implements Viewable { } public void UNSAFE_removeCustomBlock(int x, int y, int z) { - this.customBlocksId[getBlockIndex(x, y, z)] = 0; // Set to none - int index = SerializerUtils.coordToChunkIndex(x, y, z); + int index = getBlockIndex(x, y, z); + this.customBlocksId[index] = 0; // Set to none this.blocksData.remove(index); this.updatableBlocks.remove(index); @@ -102,15 +102,15 @@ public class Chunk implements Viewable { } private void setBlock(int x, int y, int z, short blockId, short customId, Data data, UpdateConsumer updateConsumer) { - int index = SerializerUtils.coordToChunkIndex(x, y, z); + int index = getBlockIndex(x, y, z); if (blockId != 0 || (blockId == 0 && customId != 0 && updateConsumer != null)) { // Allow custom air block for update purpose, refused if no update consumer has been found - refreshBlockValue(x, y, z, blockId, customId); + this.blocksId[index] = blockId; + this.customBlocksId[index] = customId; } else { // Block has been deleted, clear cache and return - this.blocksId[getBlockIndex(x, y, z)] = 0; // Set to air - //this.blocks.remove(index); + this.blocksId[index] = 0; // Set to air this.blocksData.remove(index); @@ -149,7 +149,7 @@ public class Chunk implements Viewable { } public void setBlockData(int x, int y, int z, Data data) { - int index = SerializerUtils.coordToChunkIndex(x, y, z); + int index = getBlockIndex(x, y, z); if (data != null) { this.blocksData.put(index, data); } else { @@ -185,7 +185,7 @@ public class Chunk implements Viewable { } protected CustomBlock getCustomBlock(int index) { - int[] pos = SerializerUtils.indexToChunkPosition(index); + int[] pos = ChunkUtils.indexToChunkPosition(index); return getCustomBlock(pos[0], pos[1], pos[2]); } @@ -215,7 +215,7 @@ public class Chunk implements Viewable { } public Data getData(int x, byte y, int z) { - int index = SerializerUtils.coordToChunkIndex(x, y, z); + int index = getBlockIndex(x, y, z); return getData(index); } @@ -243,12 +243,12 @@ public class Chunk implements Viewable { this.updatableBlocksLastUpdate.put(index, time); // Refresh last update time - int[] blockPos = SerializerUtils.indexToChunkPosition(index); + int[] blockPos = ChunkUtils.indexToPosition(index, chunkX, chunkZ); int x = blockPos[0]; int y = blockPos[1]; int z = blockPos[2]; - BlockPosition blockPosition = new BlockPosition(x + 16 * chunkX, y, z + 16 * chunkZ); + BlockPosition blockPosition = new BlockPosition(x, y, z); Data data = getData(index); customBlock.update(instance, blockPosition, data); } @@ -296,10 +296,10 @@ public class Chunk implements Viewable { for (byte x = 0; x < CHUNK_SIZE_X; x++) { for (short y = 0; y < CHUNK_SIZE_Y; y++) { for (byte z = 0; z < CHUNK_SIZE_Z; z++) { - int index = SerializerUtils.coordToChunkIndex(x, y, z); + int index = getBlockIndex(x, y, z); - short blockId = getBlockId(x, y, z); - short customBlockId = getCustomBlockId(x, y, z); + short blockId = blocksId[index]; + short customBlockId = customBlocksId[index]; if (blockId == 0 && customBlockId == 0) continue; @@ -334,15 +334,27 @@ public class Chunk implements Viewable { public ChunkDataPacket getFreshFullDataPacket() { ChunkDataPacket fullDataPacket = new ChunkDataPacket(); - fullDataPacket.chunk = this; fullDataPacket.fullChunk = true; + fullDataPacket.biomes = biomes.clone(); + fullDataPacket.chunkX = chunkX; + fullDataPacket.chunkZ = chunkZ; + fullDataPacket.blocksId = blocksId.clone(); + fullDataPacket.customBlocksId = customBlocksId.clone(); + fullDataPacket.blockEntities = new CopyOnWriteArraySet<>(blockEntities); + fullDataPacket.blocksData = new Int2ObjectOpenHashMap<>(blocksData); return fullDataPacket; } public ChunkDataPacket getFreshPartialDataPacket() { ChunkDataPacket fullDataPacket = new ChunkDataPacket(); - fullDataPacket.chunk = this; fullDataPacket.fullChunk = false; + fullDataPacket.biomes = biomes.clone(); + fullDataPacket.chunkX = chunkX; + fullDataPacket.chunkZ = chunkZ; + fullDataPacket.blocksId = blocksId.clone(); + fullDataPacket.customBlocksId = customBlocksId.clone(); + fullDataPacket.blockEntities = new CopyOnWriteArraySet<>(blockEntities); + fullDataPacket.blocksData = new Int2ObjectOpenHashMap<>(blocksData); return fullDataPacket; } @@ -408,13 +420,6 @@ public class Chunk implements Viewable { } private int getBlockIndex(int x, int y, int z) { - x = x % Chunk.CHUNK_SIZE_X; - z = z % Chunk.CHUNK_SIZE_Z; - - x = x < 0 ? Chunk.CHUNK_SIZE_X + x : x; - z = z < 0 ? Chunk.CHUNK_SIZE_Z + z : z; - - int index = (((y * 16) + x) * 16) + z; - return index; + return ChunkUtils.getBlockIndex(x, y, z); } } \ No newline at end of file diff --git a/src/main/java/net/minestom/server/instance/Instance.java b/src/main/java/net/minestom/server/instance/Instance.java index d4188c6bf..a0b9118ff 100644 --- a/src/main/java/net/minestom/server/instance/Instance.java +++ b/src/main/java/net/minestom/server/instance/Instance.java @@ -139,9 +139,8 @@ public abstract class Instance implements BlockModifier, EventHandler, DataConta } protected ChunkDataPacket getChunkSectionUpdatePacket(Chunk chunk, int section) { - ChunkDataPacket chunkDataPacket = new ChunkDataPacket(); + ChunkDataPacket chunkDataPacket = chunk.getFreshPartialDataPacket(); chunkDataPacket.fullChunk = false; - chunkDataPacket.chunk = chunk; int[] sections = new int[16]; sections[section] = 1; chunkDataPacket.sections = sections; diff --git a/src/main/java/net/minestom/server/instance/InstanceContainer.java b/src/main/java/net/minestom/server/instance/InstanceContainer.java index 17f8e1c82..ca83df0b1 100644 --- a/src/main/java/net/minestom/server/instance/InstanceContainer.java +++ b/src/main/java/net/minestom/server/instance/InstanceContainer.java @@ -20,7 +20,6 @@ import net.minestom.server.storage.StorageFolder; import net.minestom.server.timer.TaskRunnable; import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.Position; -import net.minestom.server.utils.SerializerUtils; import net.minestom.server.utils.chunk.ChunkUtils; import net.minestom.server.utils.player.PlayerUtils; import net.minestom.server.utils.time.TimeUnit; @@ -80,8 +79,6 @@ public class InstanceContainer extends Instance { boolean isCustomBlock = customBlock != null; - int index = SerializerUtils.coordToChunkIndex(x, y, z); - BlockPosition blockPosition = new BlockPosition(x, y, z); if (isAlreadyChanged(blockPosition, blockId)) { // do NOT change the block again. @@ -91,6 +88,8 @@ public class InstanceContainer extends Instance { } setAlreadyChanged(blockPosition, blockId); + int index = ChunkUtils.getBlockIndex(x, y, z); + // Call the destroy listener if previous block was a custom block callBlockDestroy(chunk, index, blockPosition); diff --git a/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java b/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java index d12e23ad6..e5f96ed69 100644 --- a/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java +++ b/src/main/java/net/minestom/server/network/packet/server/play/ChunkDataPacket.java @@ -1,17 +1,20 @@ package net.minestom.server.network.packet.server.play; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import net.minestom.server.MinecraftServer; import net.minestom.server.data.Data; import net.minestom.server.instance.Biome; import net.minestom.server.instance.Chunk; +import net.minestom.server.instance.block.BlockManager; import net.minestom.server.instance.block.CustomBlock; import net.minestom.server.network.packet.PacketWriter; import net.minestom.server.network.packet.server.ServerPacket; import net.minestom.server.network.packet.server.ServerPacketIdentifier; import net.minestom.server.utils.BlockPosition; -import net.minestom.server.utils.SerializerUtils; import net.minestom.server.utils.Utils; import net.minestom.server.utils.buffer.BufferUtils; import net.minestom.server.utils.buffer.BufferWrapper; +import net.minestom.server.utils.chunk.ChunkUtils; import net.querz.nbt.CompoundTag; import net.querz.nbt.DoubleTag; import net.querz.nbt.LongArrayTag; @@ -23,8 +26,19 @@ import java.util.Set; public class ChunkDataPacket implements ServerPacket { + private static final BlockManager BLOCK_MANAGER = MinecraftServer.getBlockManager(); + public boolean fullChunk; - public Chunk chunk; + public Biome[] biomes; + public int chunkX, chunkZ; + + public short[] blocksId; + public short[] customBlocksId; + + public Set blockEntities; + public Int2ObjectMap blocksData; + //public Chunk chunk; + public int[] sections; private static final byte CHUNK_SECTION_COUNT = 16; @@ -33,15 +47,15 @@ public class ChunkDataPacket implements ServerPacket { @Override public void write(PacketWriter writer) { - writer.writeInt(chunk.getChunkX()); - writer.writeInt(chunk.getChunkZ()); + writer.writeInt(chunkX); + writer.writeInt(chunkZ); writer.writeBoolean(fullChunk); int mask = 0; BufferWrapper blocks = BufferUtils.getBuffer(MAX_BUFFER_SIZE); for (byte i = 0; i < CHUNK_SECTION_COUNT; i++) { if (fullChunk || (sections.length == CHUNK_SECTION_COUNT && sections[i] != 0)) { - short[] section = getSection(chunk, i); + short[] section = getSection(i); if (section != null) { // section contains at least one block mask |= 1 << i; Utils.writeBlocks(blocks, section, BITS_PER_ENTRY); @@ -81,7 +95,6 @@ public class ChunkDataPacket implements ServerPacket { // Biome data if (fullChunk) { - Biome[] biomes = chunk.getBiomes(); for (int i = 0; i < biomes.length; i++) { writer.writeInt(biomes[i].getId()); } @@ -92,18 +105,18 @@ public class ChunkDataPacket implements ServerPacket { writer.writeBufferAndFree(blocks); // Block entities - Set blockEntities = chunk.getBlockEntities(); writer.writeVarInt(blockEntities.size()); - for (Integer index : blockEntities) { - BlockPosition blockPosition = SerializerUtils.indexToChunkBlockPosition(index); + for (int index : blockEntities) { + BlockPosition blockPosition = ChunkUtils.getBlockPosition(index, chunkX, chunkZ); CompoundTag blockEntity = new CompoundTag(); - blockEntity.put("x", new DoubleTag(blockPosition.getX() + 16 * chunk.getChunkX())); + blockEntity.put("x", new DoubleTag(blockPosition.getX())); blockEntity.put("y", new DoubleTag(blockPosition.getY())); - blockEntity.put("z", new DoubleTag(blockPosition.getZ() + 16 * chunk.getChunkZ())); - CustomBlock customBlock = chunk.getCustomBlock(blockPosition.getX(), blockPosition.getY(), blockPosition.getZ()); + blockEntity.put("z", new DoubleTag(blockPosition.getZ())); + short customBlockId = customBlocksId[index]; + CustomBlock customBlock = BLOCK_MANAGER.getCustomBlock(customBlockId); if (customBlock != null) { - Data data = chunk.getData(blockPosition.getX(), (byte) blockPosition.getY(), blockPosition.getZ()); + Data data = blocksData.get(index); customBlock.writeBlockEntity(blockPosition, data, blockEntity); } ByteArrayOutputStream os = new ByteArrayOutputStream(); @@ -117,18 +130,20 @@ public class ChunkDataPacket implements ServerPacket { } } - private short[] getSection(Chunk chunk, byte section) { + private short[] getSection(byte section) { short[] blocks = new short[Chunk.CHUNK_SIZE_X * Chunk.CHUNK_SECTION_SIZE * Chunk.CHUNK_SIZE_Z]; boolean empty = true; for (byte y = 0; y < Chunk.CHUNK_SECTION_SIZE; y++) { for (byte x = 0; x < Chunk.CHUNK_SIZE_X; x++) { for (byte z = 0; z < Chunk.CHUNK_SIZE_Z; z++) { - short blockId = chunk.getBlockId(x, (y + Chunk.CHUNK_SECTION_SIZE * section), z); + int yPos = (y + Chunk.CHUNK_SECTION_SIZE * section); + int index = ChunkUtils.getBlockIndex(x, yPos, z); + short blockId = blocksId[index]; if (blockId != 0) empty = false; - int index = (((y * 16) + x) * 16) + z; - blocks[index] = blockId; + int packetIndex = (((y * 16) + x) * 16) + z; + blocks[packetIndex] = blockId; } } } diff --git a/src/main/java/net/minestom/server/utils/SerializerUtils.java b/src/main/java/net/minestom/server/utils/SerializerUtils.java index b90eebab9..b2b0a5a33 100644 --- a/src/main/java/net/minestom/server/utils/SerializerUtils.java +++ b/src/main/java/net/minestom/server/utils/SerializerUtils.java @@ -1,46 +1,7 @@ package net.minestom.server.utils; -import net.minestom.server.instance.Chunk; - public class SerializerUtils { - public static byte[] intToBytes(int value) { - byte[] result = new byte[4]; - result[0] = (byte) (value >> 24); - result[1] = (byte) (value >> 16); - result[2] = (byte) (value >> 8); - result[3] = (byte) (value >> 0); - return result; - } - - public static int bytesToInt(byte[] value) { - return ((value[0] & 0xFF) << 24) | - ((value[1] & 0xFF) << 16) | - ((value[2] & 0xFF) << 8) | - ((value[3] & 0xFF) << 0); - } - - public static int coordToChunkIndex(int x, int y, int z) { - x = x % Chunk.CHUNK_SIZE_X; - z = z % Chunk.CHUNK_SIZE_Z; - short index = (short) (x & 0x000F); - index |= (y << 4) & 0x0FF0; - index |= (z << 12) & 0xF000; - return index & 0xffff; - } - - public static int[] indexToChunkPosition(int index) { - int z = (byte) (index >> 12 & 0xF); - int y = (index >>> 4 & 0xFF); - int x = (byte) (index >> 0 & 0xF); - return new int[]{x, y, z}; - } - - public static BlockPosition indexToChunkBlockPosition(int index) { - int[] pos = indexToChunkPosition(index); - return new BlockPosition(pos[0], pos[1], pos[2]); - } - public static long positionToLong(int x, int y, int z) { return (((long) x & 0x3FFFFFF) << 38) | (((long) z & 0x3FFFFFF) << 12) | ((long) y & 0xFFF); } diff --git a/src/main/java/net/minestom/server/utils/chunk/ChunkUtils.java b/src/main/java/net/minestom/server/utils/chunk/ChunkUtils.java index aa5592ff6..cd2780446 100644 --- a/src/main/java/net/minestom/server/utils/chunk/ChunkUtils.java +++ b/src/main/java/net/minestom/server/utils/chunk/ChunkUtils.java @@ -2,6 +2,7 @@ package net.minestom.server.utils.chunk; import net.minestom.server.instance.Chunk; import net.minestom.server.instance.Instance; +import net.minestom.server.utils.BlockPosition; import net.minestom.server.utils.MathUtils; import net.minestom.server.utils.Position; @@ -83,4 +84,34 @@ public class ChunkUtils { return visibleChunks; } + public static int getBlockIndex(int x, int y, int z) { + x = x % Chunk.CHUNK_SIZE_X; + z = z % Chunk.CHUNK_SIZE_Z; + + short index = (short) (x & 0x000F); + index |= (y << 4) & 0x0FF0; + index |= (z << 12) & 0xF000; + return index & 0xffff; + } + + public static BlockPosition getBlockPosition(int index, int chunkX, int chunkZ) { + int[] pos = indexToPosition(index, chunkX, chunkZ); + return new BlockPosition(pos[0], pos[1], pos[2]); + } + + public static int[] indexToPosition(int index, int chunkX, int chunkZ) { + int z = (byte) (index >> 12 & 0xF); + int y = (index >>> 4 & 0xFF); + int x = (byte) (index >> 0 & 0xF); + + x += 16 * chunkX; + z += 16 * chunkZ; + + return new int[]{x, y, z}; + } + + public static int[] indexToChunkPosition(int index) { + return indexToPosition(index, 0, 0); + } + } diff --git a/src/main/java/net/minestom/server/utils/item/NbtReaderUtils.java b/src/main/java/net/minestom/server/utils/item/NbtReaderUtils.java index 073645009..234725e68 100644 --- a/src/main/java/net/minestom/server/utils/item/NbtReaderUtils.java +++ b/src/main/java/net/minestom/server/utils/item/NbtReaderUtils.java @@ -15,7 +15,7 @@ public class NbtReaderUtils { byte typeId = reader.readByte(); - System.out.println("DEBUG TYPE: " + typeId); + //System.out.println("DEBUG TYPE: " + typeId); switch (typeId) { case 0x00: // TAG_End // End of item NBT