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);
- }
- }
-}