From 72b7b22e320a0b9e3c10d169f3c73380815f5452 Mon Sep 17 00:00:00 2001 From: DmitriyMX Date: Thu, 24 Jun 2021 13:17:52 +0300 Subject: [PATCH] =?UTF-8?q?=D0=BE=D1=82=D0=BA=D0=B0=D0=B7=D1=8B=D0=B2?= =?UTF-8?q?=D0=B0=D0=B5=D0=BC=D1=81=D1=8F=20=D0=BE=D1=82=20Palette=20?= =?UTF-8?q?=D0=B2=20=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D1=83=20Direct=20mode?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../packets/play/server/ChunkDataPacket.java | 84 +++++-------------- .../mc/protocol/utils/Bit13LongArray.java | 50 +++++++++++ .../java/mc/protocol/utils/HalfByteArray.java | 38 +++++++++ .../java/mc/protocol/utils/NibbleArray.java | 54 +----------- .../protocol/utils/PaletteChunkSection.java | 77 ----------------- 5 files changed, 114 insertions(+), 189 deletions(-) create mode 100644 protocol/src/main/java/mc/protocol/utils/Bit13LongArray.java create mode 100644 protocol/src/main/java/mc/protocol/utils/HalfByteArray.java delete mode 100644 protocol/src/main/java/mc/protocol/utils/PaletteChunkSection.java diff --git a/protocol/src/main/java/mc/protocol/packets/play/server/ChunkDataPacket.java b/protocol/src/main/java/mc/protocol/packets/play/server/ChunkDataPacket.java index fa4370a..d0c07c6 100644 --- a/protocol/src/main/java/mc/protocol/packets/play/server/ChunkDataPacket.java +++ b/protocol/src/main/java/mc/protocol/packets/play/server/ChunkDataPacket.java @@ -6,10 +6,9 @@ import lombok.Getter; import lombok.RequiredArgsConstructor; import mc.protocol.buffer.NetByteBuf; import mc.protocol.packets.ServerSidePacket; -import mc.protocol.pool.ProtocolObjectPool; +import mc.protocol.utils.Bit13LongArray; +import mc.protocol.utils.HalfByteArray; import mc.protocol.utils.NibbleArray; -import mc.protocol.utils.PaletteChunkSection; -import mc.protocol.utils.PaletteChunkSection.PaletteCoords; import mc.protocol.world.Block; import mc.protocol.world.Chunk; import mc.protocol.world.ChunkSection; @@ -79,14 +78,18 @@ import mc.protocol.world.ChunkSection; @Data public class ChunkDataPacket implements ServerSidePacket { + private static final int BITS_PER_BLOCK = 13; private static final int FULL_BIT_MASK = 0b11111111_11111111; private static final int _16_16_16 = 16 * 16 * 16; - private static final int SIZE_OF_LONG_IN_BITS = 64; private Chunk chunk; @Override public void writeSelf(NetByteBuf netByteBuf) { + /* + TODO необходимо наладить работу objectpool при записи пакета + */ + netByteBuf.writeInt(chunk.getX()); // Chunk X netByteBuf.writeInt(chunk.getZ()); // Chunk Z @@ -146,63 +149,35 @@ public class ChunkDataPacket implements ServerSidePacket { // NetByteBuf data = ProtocolObjectPool.getNetByteBufPool().borrowObject().setByteBuf(Unpooled.buffer()); NetByteBuf data = new NetByteBuf().setByteBuf(Unpooled.buffer()); - PaletteChunkSection paletteSection = new PaletteChunkSection(); - NibbleArray blockLight = new NibbleArray(); - NibbleArray skyLight = new NibbleArray(); - fillPalette(section, paletteSection, blockLight, skyLight); + NibbleArray blockLight = new HalfByteArray(2048); + NibbleArray skyLight = new HalfByteArray(2048); // - int bitsPerBlock = paletteSection.bitsPerBlock(); - data.writeUnsignedByte(bitsPerBlock); + data.writeUnsignedByte(BITS_PER_BLOCK); // // - paletteSection.writePalette(data); + data.writeVarInt(0); // Direct mode // // - int dataLength = (_16_16_16 * bitsPerBlock) / SIZE_OF_LONG_IN_BITS; - data.writeVarInt(dataLength); + int dataArraySize = _16_16_16 * BITS_PER_BLOCK; + data.writeVarInt(dataArraySize / Long.SIZE); // // - //TODO алгоритм побитовой записи в long вынести в utils - // Возможно даже пораднив с NibbleArray - int lastPos = 0; - long value = 0; - boolean fairy = false; - long fairyValue = 0; + NibbleArray dataArray = new Bit13LongArray(dataArraySize); boolean writeBiomes = biomes != null; for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { for (int x = 0; x < 16; x++) { - //@formatter:off - int blockNumber = (((y << 4) + z) << 4) + x; - int startLong = ( blockNumber * bitsPerBlock ) / SIZE_OF_LONG_IN_BITS; - int startOffset = ( blockNumber * bitsPerBlock ) % SIZE_OF_LONG_IN_BITS; - int endLong = ((blockNumber + 1) * bitsPerBlock - 1) / SIZE_OF_LONG_IN_BITS; - //@formatter:on + Block block = section.getBlock(x, y, z); + int blockState = (block.getId() << 4) | block.getMeta(); + dataArray.put(blockState); - long idxBlockInPalette = paletteSection.getIndexBlockInPalette(x, y, z); - - if (startLong != lastPos) { - data.writeLong(value); - lastPos = startLong; - if (fairy) { - value = fairyValue; - fairy = false; - } else { - value = 0; - } - } - - value |= (idxBlockInPalette << startOffset); - - if (startLong != endLong) { - fairyValue = idxBlockInPalette >> (SIZE_OF_LONG_IN_BITS - startOffset); - fairy = true; - } + blockLight.put(block.getLight()); + skyLight.put(section.getSkyLight(x, y, z)); if (writeBiomes) { biomes.writeByte(chunk.getBiome( @@ -216,35 +191,20 @@ public class ChunkDataPacket implements ServerSidePacket { } } } - data.writeLong(value); + data.writeBytes(dataArray.byteBuffer()); // // - data.writeBytes(blockLight.getRawData()); + data.writeBytes(blockLight.byteBuffer()); // // - data.writeBytes(skyLight.getRawData()); + data.writeBytes(skyLight.byteBuffer()); // return data; } - private void fillPalette(ChunkSection section, PaletteChunkSection paletteSection, NibbleArray blockLight, NibbleArray skyLight) { - for (int y = 0; y < 16; y++) { - for (int z = 0; z < 16; z++) { - for (int x = 0; x < 16; x++) { - Block block = section.getBlock(x, y, z); - PaletteCoords paletteCoords = PaletteCoords.createByBlock(block); - - paletteSection.addBlock(x, y, z, block); - blockLight.set(paletteCoords.getX(), paletteCoords.getY(), paletteCoords.getZ(), block.getLight()); - skyLight.set(paletteCoords.getX(), paletteCoords.getY(), paletteCoords.getZ(), section.getSkyLight(x, y, z)); - } - } - } - } - @RequiredArgsConstructor @Getter private static class AvailableSections { diff --git a/protocol/src/main/java/mc/protocol/utils/Bit13LongArray.java b/protocol/src/main/java/mc/protocol/utils/Bit13LongArray.java new file mode 100644 index 0000000..f3041cb --- /dev/null +++ b/protocol/src/main/java/mc/protocol/utils/Bit13LongArray.java @@ -0,0 +1,50 @@ +package mc.protocol.utils; + +import java.nio.ByteBuffer; + +public class Bit13LongArray implements NibbleArray { + + private static final int BITS = 13; + private final ByteBuffer buffer; + + private long longValue = 0L; + private int nibbleIndex = 0; + private int lastWriteIndex = 0; + + public Bit13LongArray(int capacity) { + this.buffer = ByteBuffer.allocate(capacity); + } + + @Override + public void put(int value) { + if (Integer.bitCount(value) > BITS) { + throw new IllegalArgumentException("Value is to big: " + value); + } + + //@formetter:off + int headValueIndex = ((nibbleIndex + 1) * BITS - 1) / Long.SIZE; + int tailValueIndex = ((nibbleIndex ) * BITS ) / Long.SIZE; + int offsetValue = ((nibbleIndex ) * BITS ) % Long.SIZE; + //@formetter:on + + if (tailValueIndex != lastWriteIndex) { + buffer.asLongBuffer().put(longValue); + lastWriteIndex++; + longValue = 0L; + } + + longValue |= ((long) value << offsetValue); + nibbleIndex++; + + if (headValueIndex != tailValueIndex) { + buffer.asLongBuffer().put(longValue); + lastWriteIndex++; + longValue = value >> (Long.SIZE - offsetValue); + } + } + + @Override + public ByteBuffer byteBuffer() { + return this.buffer.rewind(); + } +} diff --git a/protocol/src/main/java/mc/protocol/utils/HalfByteArray.java b/protocol/src/main/java/mc/protocol/utils/HalfByteArray.java new file mode 100644 index 0000000..ad0192e --- /dev/null +++ b/protocol/src/main/java/mc/protocol/utils/HalfByteArray.java @@ -0,0 +1,38 @@ +package mc.protocol.utils; + +import java.nio.ByteBuffer; + +public class HalfByteArray implements NibbleArray { + + private static final int BITS = 4; + private final ByteBuffer buffer; + private Byte halfValue = null; + + public HalfByteArray(int capacity) { + this.buffer = ByteBuffer.allocate(capacity); + } + + @Override + public void put(int value) { + if (Integer.bitCount(value) > BITS) { + throw new IllegalArgumentException("Value is to big: " + value); + } + + if (halfValue == null) { + halfValue = (byte) (value << BITS); + } else { + buffer.put((byte) (halfValue | value)); + halfValue = null; + } + } + + @Override + public ByteBuffer byteBuffer() { + if (halfValue != null) { + buffer.put(halfValue); + halfValue = null; + } + + return this.buffer.rewind(); + } +} diff --git a/protocol/src/main/java/mc/protocol/utils/NibbleArray.java b/protocol/src/main/java/mc/protocol/utils/NibbleArray.java index 20acdb6..4714ccb 100644 --- a/protocol/src/main/java/mc/protocol/utils/NibbleArray.java +++ b/protocol/src/main/java/mc/protocol/utils/NibbleArray.java @@ -1,56 +1,10 @@ package mc.protocol.utils; -import lombok.RequiredArgsConstructor; +import java.nio.ByteBuffer; -@RequiredArgsConstructor -public class NibbleArray { +public interface NibbleArray { - private final byte[] data; + void put(int value); - public NibbleArray(int capacity) { - this.data = new byte[capacity]; - } - - public NibbleArray() { - this(2048); - } - - public int get(int x, int y, int z) { - int idx = coordsToIndex(x, y, z); - - int ni = nibbleIndex(idx); - return isLowerNibble(idx) ? this.data[ni] & 0x0F : this.data[ni] >> 4 & 0x0F; - } - - public void set(int x, int y, int z, int value) { - //@formatter:off - if (value < 0) value = 0; - else if (value > 15) value = 15; - //@formatter:on - - int idx = coordsToIndex(x, y, z); - int ni = nibbleIndex(idx); - - if (isLowerNibble(idx)) { - this.data[ni] = (byte) (value); - } else { - this.data[ni] = (byte) (this.data[ni] | value << 4); - } - } - - public byte[] getRawData() { - return data; - } - - private int coordsToIndex(int x, int y, int z) { - return y << 8 | z << 4 | x; - } - - private int nibbleIndex(int index) { - return index >> 1; - } - - private boolean isLowerNibble(int index) { - return (index & 1) == 0; - } + ByteBuffer byteBuffer(); } diff --git a/protocol/src/main/java/mc/protocol/utils/PaletteChunkSection.java b/protocol/src/main/java/mc/protocol/utils/PaletteChunkSection.java deleted file mode 100644 index 2638f32..0000000 --- a/protocol/src/main/java/mc/protocol/utils/PaletteChunkSection.java +++ /dev/null @@ -1,77 +0,0 @@ -package mc.protocol.utils; - -import lombok.AccessLevel; -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import mc.protocol.buffer.NetByteBuf; -import mc.protocol.world.Block; - -import java.util.ArrayList; -import java.util.List; - -public class PaletteChunkSection { - - private final byte[] blocks = new byte[4096]; - private final List palette = new ArrayList<>(); - - public void addBlock(int x, int y, int z, Block block) { - blocks[coordsToIndex(x, y, z)] = putPalette(block); - } - - public int bitsPerBlock() { - if (palette.size() <= 15) { - return 4; - } else if (palette.size() <= 31) { - return 5; - } else if (palette.size() <= 63) { - return 6; - } else if (palette.size() <= 127) { - return 7; - } else if (palette.size() <= 255) { - return 8; - } else { - return 13; - } - } - - public void writePalette(NetByteBuf netByteBuf) { - netByteBuf.writeVarInt(palette.size()); // Size of palette - palette.forEach(netByteBuf::writeVarInt); // Palette - } - - public long getIndexBlockInPalette(int x, int y, int z) { - return blocks[coordsToIndex(x, y, z)]; - } - - private int coordsToIndex(int x, int y, int z) { - return y << 8 | z << 4 | x; - } - - private byte putPalette(Block block) { - int blockState = (block.getId() << 4) | block.getMeta(); - - int idx = palette.indexOf(blockState); - if (idx == -1) { - palette.add(blockState); - idx = palette.size() - 1; - } - - return (byte) idx; - } - - @RequiredArgsConstructor(access = AccessLevel.PRIVATE) - @Getter - public static class PaletteCoords { - private final int x; - private final int y; - private final int z; - - public static PaletteCoords createByBlock(Block block) { - int bx = (int) block.getLocation().getX() - (((int) block.getLocation().getX() >> 4) << 4); - int by = (int) block.getLocation().getY() - (((int) block.getLocation().getY() >> 4) << 4); - int bz = (int) block.getLocation().getZ() - (((int) block.getLocation().getZ() >> 4) << 4); - - return new PaletteCoords(bx, by, bz); - } - } -}