сериализация полного чанка
This commit is contained in:
@@ -2,17 +2,12 @@ package mc.protocol.packets.play.server;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import mc.protocol.buffer.NetByteBuf;
|
||||
import mc.protocol.packets.ServerSidePacket;
|
||||
import mc.protocol.pool.ProtocolObjectPool;
|
||||
import mc.protocol.world.Block;
|
||||
import mc.protocol.utils.ChunkSerializeUtil;
|
||||
import mc.protocol.world.Chunk;
|
||||
import mc.protocol.world.ChunkSection;
|
||||
import mc.utils.array.BitArray;
|
||||
import mc.utils.array.BitByteArray;
|
||||
import mc.utils.array.BitLongArray;
|
||||
|
||||
/**
|
||||
* Данные чанка.
|
||||
@@ -79,9 +74,7 @@ import mc.utils.array.BitLongArray;
|
||||
@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 Chunk chunk;
|
||||
|
||||
@@ -90,12 +83,10 @@ public class ChunkDataPacket implements ServerSidePacket {
|
||||
netByteBuf.writeInt(chunk.getX()); // Chunk X
|
||||
netByteBuf.writeInt(chunk.getZ()); // Chunk Z
|
||||
|
||||
AvailableSections availableSections = createAvailableSections();
|
||||
boolean fullChunk = availableSections.getBitMask() == FULL_BIT_MASK;
|
||||
netByteBuf.writeBoolean(fullChunk); // Is Full chunk
|
||||
netByteBuf.writeVarInt(availableSections.getBitMask()); // Available Sections
|
||||
netByteBuf.writeBoolean(true); // Is Full chunk
|
||||
netByteBuf.writeVarInt(FULL_BIT_MASK); // Available Sections
|
||||
|
||||
NetByteBuf data = createDataStructure(availableSections.getMaxHeight(), fullChunk);
|
||||
NetByteBuf data = createDataStructure();
|
||||
netByteBuf.writeVarInt(data.readableBytes()); // Size of Data
|
||||
netByteBuf.writeBytes(data); // Data
|
||||
|
||||
@@ -105,108 +96,26 @@ public class ChunkDataPacket implements ServerSidePacket {
|
||||
ProtocolObjectPool.getNetByteBufPool().returnObject(data);
|
||||
}
|
||||
|
||||
private AvailableSections createAvailableSections() {
|
||||
int bitMask = 0;
|
||||
int maxH = 0;
|
||||
for (int h = 15; h >= 0; h--) {
|
||||
bitMask = bitMask << 1;
|
||||
ChunkSection chunkSection = chunk.getSection(h);
|
||||
if (chunkSection != null && chunkSection.getY() == h) {
|
||||
bitMask |= 0x01;
|
||||
maxH++;
|
||||
} else {
|
||||
bitMask |= 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
return new AvailableSections(bitMask, maxH);
|
||||
}
|
||||
|
||||
private NetByteBuf createDataStructure(int maxHeight, boolean fillBiomes) {
|
||||
private NetByteBuf createDataStructure() {
|
||||
NetByteBuf dataStructure = ProtocolObjectPool.getNetByteBufPool().borrowObject().setByteBuf(Unpooled.buffer());
|
||||
NetByteBuf biomes = fillBiomes ? ProtocolObjectPool.getNetByteBufPool().borrowObject().setByteBuf(Unpooled.buffer()) : null;
|
||||
|
||||
for (int h = 0; h < maxHeight; h++) {
|
||||
for (int h = 0; h < 16; h++) {
|
||||
ChunkSection section = chunk.getSection(h);
|
||||
if (section == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
NetByteBuf data = createData(section, biomes);
|
||||
NetByteBuf data = ChunkSerializeUtil.serializeSection(section);
|
||||
dataStructure.writeBytes(data); // Data
|
||||
ProtocolObjectPool.getNetByteBufPool().returnObject(data);
|
||||
}
|
||||
|
||||
if (fillBiomes) {
|
||||
dataStructure.writeBytes(biomes); // Biomes
|
||||
ProtocolObjectPool.getNetByteBufPool().returnObject(biomes);
|
||||
// <Biomes>
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
dataStructure.writeByte(chunk.getBiome(
|
||||
(chunk.getX() << 4) + x,
|
||||
(chunk.getZ() << 4) + z));
|
||||
}
|
||||
}
|
||||
// </Biomes>
|
||||
|
||||
return dataStructure;
|
||||
}
|
||||
|
||||
private NetByteBuf createData(ChunkSection section, NetByteBuf biomes) {
|
||||
NetByteBuf data = ProtocolObjectPool.getNetByteBufPool().borrowObject().setByteBuf(Unpooled.buffer());
|
||||
|
||||
BitArray blockLight = new BitByteArray(4, 2048 * 2);
|
||||
BitArray skyLight = new BitByteArray(4, 2048 * 2);
|
||||
|
||||
// <Bits Per Block>
|
||||
data.writeUnsignedByte(BITS_PER_BLOCK);
|
||||
// </Bits Per Block>
|
||||
|
||||
// <Palette>
|
||||
data.writeVarInt(0); // Direct mode
|
||||
// </Palette>
|
||||
|
||||
// <Data Array Length>
|
||||
data.writeVarInt(_16_16_16);
|
||||
// </Data Array Length>
|
||||
|
||||
// <Data Array>
|
||||
BitArray dataArray = new BitLongArray(BITS_PER_BLOCK, _16_16_16);
|
||||
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++) {
|
||||
Block block = section.getBlock(x, y, z);
|
||||
int blockState = (block.getId() << 4) | block.getMeta();
|
||||
dataArray.put(blockState);
|
||||
|
||||
blockLight.put(block.getLight());
|
||||
skyLight.put(section.getSkyLight(x, y, z));
|
||||
|
||||
if (writeBiomes) {
|
||||
biomes.writeByte(chunk.getBiome(
|
||||
(chunk.getX() << 4) + x,
|
||||
(chunk.getZ() << 4) + z));
|
||||
|
||||
if (x == 15 && z == 15) {
|
||||
writeBiomes = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
data.writeBytes(dataArray.byteBuffer());
|
||||
// </Data Array>
|
||||
|
||||
// <Block Light>
|
||||
data.writeBytes(blockLight.byteBuffer());
|
||||
// </Block Light>
|
||||
|
||||
// <Sky Light>
|
||||
data.writeBytes(skyLight.byteBuffer());
|
||||
// </Sky Light>
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Getter
|
||||
private static class AvailableSections {
|
||||
private final int bitMask;
|
||||
private final int maxHeight;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
package mc.protocol.utils;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.NoArgsConstructor;
|
||||
import mc.protocol.buffer.NetByteBuf;
|
||||
import mc.protocol.pool.ProtocolObjectPool;
|
||||
import mc.protocol.world.Block;
|
||||
import mc.protocol.world.ChunkSection;
|
||||
import mc.utils.array.BitArray;
|
||||
import mc.utils.array.BitByteArray;
|
||||
import mc.utils.array.BitLongArray;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
public final class ChunkSerializeUtil {
|
||||
|
||||
private static final int BITS_PER_BLOCK = 13;
|
||||
private static final int ALL_BLOCKS = 16 * 16 * 16;
|
||||
|
||||
public static NetByteBuf serializeSection(ChunkSection section) {
|
||||
BitArray blockArray = new BitLongArray(BITS_PER_BLOCK, ALL_BLOCKS);
|
||||
BitArray blockLight = new BitByteArray(4, ALL_BLOCKS);
|
||||
BitArray skyLight = new BitByteArray(4, ALL_BLOCKS);
|
||||
|
||||
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);
|
||||
int blockState = (block.getId() << 4) | block.getMeta();
|
||||
|
||||
blockArray.put(blockState);
|
||||
blockLight.put(block.getLight());
|
||||
skyLight.put(section.getSkyLight(x, y, z));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NetByteBuf result = ProtocolObjectPool.getNetByteBufPool().borrowObject().setByteBuf(Unpooled.buffer());
|
||||
result.writeUnsignedByte(BITS_PER_BLOCK); // Bits Per Block
|
||||
result.writeVarInt(0); // Palette, Direct mode
|
||||
result.writeVarInt(blockArray.size()); // Data Array Length
|
||||
result.writeBytes(blockArray.byteBuffer()); // Data Array
|
||||
result.writeBytes(blockLight.byteBuffer()); // Block Light
|
||||
result.writeBytes(skyLight.byteBuffer()); // Sky Light
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user