оптимизирован и исправлен алгоритм сериализации чанка
This commit is contained in:
@@ -6,4 +6,5 @@ dependencies {
|
||||
|
||||
/* Components */
|
||||
compile (group: 'com.google.code.gson', name: 'gson', version: '2.8.5')
|
||||
compile (group: 'net.sf.trove4j', name: 'trove4j', version: '3.0.3')
|
||||
}
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
/*
|
||||
* DmitriyMX <dimon550@gmail.com>
|
||||
* 2018-07-21
|
||||
*/
|
||||
package mc.core.network.proto_1_12_2.packets;
|
||||
|
||||
import gnu.trove.list.TIntList;
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
@@ -15,7 +13,6 @@ import mc.core.world.block.BlockType;
|
||||
import mc.core.world.chunk.Chunk;
|
||||
import mc.core.world.chunk.ChunkSection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
@@ -80,10 +77,6 @@ public class ChunkDataPacket implements SCPacket {
|
||||
private Chunk chunk;
|
||||
private List<ChunkSection> sectionList;
|
||||
|
||||
private int serializeBlockState(BlockType blockType) {
|
||||
return (blockType.getId() << 4) | blockType.getMeta();
|
||||
}
|
||||
|
||||
public void setChunk(Chunk chunk) {
|
||||
this.sectionList = null;
|
||||
this.chunk = chunk;
|
||||
@@ -96,13 +89,18 @@ public class ChunkDataPacket implements SCPacket {
|
||||
|
||||
@Override
|
||||
public void writeSelf(NetOutputStream netStream) {
|
||||
if (sectionList == null && chunk == null) {
|
||||
log.warn("Empty chunk data!"); //TODO для такого нужна заглушка
|
||||
return;
|
||||
}
|
||||
|
||||
netStream.writeInt(x); // Chunk X
|
||||
netStream.writeInt(z); // Chunk Y
|
||||
netStream.writeBoolean(initChunk); // Init Chunk
|
||||
|
||||
int maxH = 0;
|
||||
if (sectionList == null && chunk != null) {
|
||||
int bitMask = 0;
|
||||
if (sectionList == null && chunk != null) {
|
||||
for (int h = 15; h >= 0; h--) {
|
||||
bitMask = bitMask << 1;
|
||||
ChunkSection chunkSection = chunk.getChunkSection(h);
|
||||
@@ -113,11 +111,8 @@ public class ChunkDataPacket implements SCPacket {
|
||||
bitMask |= 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
netStream.writeVarInt(bitMask); // Primary Bit Mask
|
||||
} else if (sectionList != null && chunk == null) {
|
||||
sectionList.sort(Comparator.comparingInt(ChunkSection::getY));
|
||||
int bitMask = 0;
|
||||
for (int h = 15, i = 0; h >= 0; h--) {
|
||||
bitMask = bitMask << 1;
|
||||
ChunkSection chunkSection = sectionList.get(i);
|
||||
@@ -128,16 +123,13 @@ public class ChunkDataPacket implements SCPacket {
|
||||
bitMask |= 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
netStream.writeVarInt(bitMask); // Primary Bit Mask
|
||||
} else {
|
||||
log.warn("Empty chunk data");
|
||||
return;
|
||||
}
|
||||
netStream.writeVarInt(bitMask); // Primary Bit Mask
|
||||
|
||||
final ByteArrayOutputNetStream data = new ByteArrayOutputNetStream();
|
||||
int dataItems = 0;
|
||||
final int airBlockPalette = serializeBlockState(BlockType.AIR);
|
||||
|
||||
final ByteArrayOutputNetStream biomes = new ByteArrayOutputNetStream();
|
||||
boolean biomeWrite = true;
|
||||
|
||||
for (int h = 0; h < maxH; h++) {
|
||||
ChunkSection chunkSection = null;
|
||||
@@ -152,64 +144,19 @@ public class ChunkDataPacket implements SCPacket {
|
||||
continue;
|
||||
}
|
||||
|
||||
final List<Integer> palette = new ArrayList<>();
|
||||
palette.add(airBlockPalette);
|
||||
final ByteArrayOutputNetStream dataArray = new ByteArrayOutputNetStream();
|
||||
final ByteArrayOutputNetStream blockLight = new ByteArrayOutputNetStream();
|
||||
final ByteArrayOutputNetStream skyLight = new ByteArrayOutputNetStream();
|
||||
final ByteArrayOutputNetStream biomes = new ByteArrayOutputNetStream();
|
||||
|
||||
long dataValueCompacted = 0;
|
||||
int blockLightCompacted = 0;
|
||||
int skyLightCompacted = 0;
|
||||
|
||||
int idxHalfLong = 0;
|
||||
int idxHalfByte = 0;
|
||||
boolean biomeFinally = false;
|
||||
final PalettedChunkSection palettedChunkSection = new PalettedChunkSection();
|
||||
palettedChunkSection.addBlockType(BlockType.AIR);
|
||||
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
Block block = chunkSection.getBlock(x, y, z);
|
||||
int blockState = serializeBlockState(block.getBlockType());
|
||||
palettedChunkSection.addBlock(chunkSection.getBlock(x, y, z));
|
||||
palettedChunkSection.addSkyLight(chunkSection.getSkyLight(x, y, z));
|
||||
|
||||
int currentIndexPaletteBlock;
|
||||
if (!palette.contains(blockState)) {
|
||||
palette.add(blockState);
|
||||
currentIndexPaletteBlock = palette.size()-1;
|
||||
} else {
|
||||
currentIndexPaletteBlock = palette.indexOf(blockState);
|
||||
}
|
||||
|
||||
if (idxHalfLong == 0) {
|
||||
dataValueCompacted = currentIndexPaletteBlock;
|
||||
idxHalfLong++;
|
||||
} else if (idxHalfLong > 0 && idxHalfLong < 15) {
|
||||
dataValueCompacted = (dataValueCompacted << 4) | currentIndexPaletteBlock;
|
||||
idxHalfLong++;
|
||||
} else {
|
||||
dataValueCompacted = (dataValueCompacted << 4) | currentIndexPaletteBlock;
|
||||
dataArray.writeLong(dataValueCompacted);
|
||||
idxHalfLong = 0;
|
||||
dataItems++;
|
||||
}
|
||||
|
||||
if (idxHalfByte == 0) {
|
||||
blockLightCompacted = block.getLight();
|
||||
skyLightCompacted = chunkSection.getSkyLight(x, y, z);
|
||||
idxHalfByte++;
|
||||
} else {
|
||||
blockLightCompacted = (blockLightCompacted << 4) | block.getLight();
|
||||
blockLight.writeByte(blockLightCompacted);
|
||||
skyLightCompacted = (skyLightCompacted << 4) | chunkSection.getSkyLight(x, y, z);
|
||||
skyLight.writeByte(skyLightCompacted);
|
||||
idxHalfByte = 0;
|
||||
}
|
||||
|
||||
if (!biomeFinally) {
|
||||
if (biomeWrite) {
|
||||
biomes.writeByte(chunkSection.getBiome(x, z).getId());
|
||||
if (x == 15 && z == 15) {
|
||||
biomeFinally = true;
|
||||
biomeWrite = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,30 +164,109 @@ public class ChunkDataPacket implements SCPacket {
|
||||
}
|
||||
|
||||
// <Chunk Section>
|
||||
// <Palette>
|
||||
data.writeUnsignedByte(4); // Bits Per Block
|
||||
data.writeVarInt(palette.size()); // Size of palette
|
||||
palette.forEach(data::writeVarInt); // Palette
|
||||
// </Palette>
|
||||
// <Data Array>
|
||||
data.writeVarInt(dataItems); // Size of Data Array
|
||||
data.writeBytes(dataArray.toByteArray()); // Data Array
|
||||
// </Data Array>
|
||||
// <Block Light>
|
||||
data.writeBytes(blockLight.toByteArray());
|
||||
// </Block Light>
|
||||
// <Sky Light>
|
||||
data.writeBytes(skyLight.toByteArray());
|
||||
// </Sky Light>
|
||||
palettedChunkSection.writeToNetStream(data);
|
||||
// </Chunk Section>
|
||||
}
|
||||
// <Biomes>
|
||||
data.writeBytes(biomes.toByteArray());
|
||||
// </Biomes>
|
||||
}
|
||||
|
||||
netStream.writeVarInt(data.size()); // Size of Data
|
||||
netStream.writeBytes(data.toByteArray()); // Data
|
||||
netStream.writeVarInt(0); // Number of block entities
|
||||
/* writeNBT */
|
||||
}
|
||||
|
||||
private class PalettedChunkSection {
|
||||
private TIntList palette = new TIntArrayList();
|
||||
private int dataItems = 0;
|
||||
private ByteArrayOutputNetStream dataArray = new ByteArrayOutputNetStream();
|
||||
private ByteArrayOutputNetStream blockLight = new ByteArrayOutputNetStream();
|
||||
private ByteArrayOutputNetStream skyLight = new ByteArrayOutputNetStream();
|
||||
|
||||
private int idxHalfLong = 0;
|
||||
private int idxHalfByte1 = 0;
|
||||
private int idxHalfByte2 = 0;
|
||||
|
||||
private long dataValueCompacted = 0;
|
||||
private int blockLightCompacted = 0;
|
||||
private int skyLightCompacted = 0;
|
||||
|
||||
private int serializeBlockState(BlockType blockType) {
|
||||
return (blockType.getId() << 4) | blockType.getMeta();
|
||||
}
|
||||
|
||||
int addBlockType(BlockType blockType) {
|
||||
int blockState = serializeBlockState(blockType);
|
||||
|
||||
int idx;
|
||||
if (!palette.contains(blockState)) {
|
||||
palette.add(blockState);
|
||||
idx = palette.size()-1;
|
||||
} else {
|
||||
idx = palette.indexOf(blockState);
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
void addBlock(Block block) {
|
||||
int idx = addBlockType(block.getBlockType());
|
||||
|
||||
//TODO нужно убрать этот позор
|
||||
// block data
|
||||
if (idxHalfLong == 0) {
|
||||
dataValueCompacted = idx;
|
||||
idxHalfLong++;
|
||||
} else if (idxHalfLong > 0 && idxHalfLong < 15) {
|
||||
dataValueCompacted = (dataValueCompacted << 4) | idx;
|
||||
idxHalfLong++;
|
||||
} else {
|
||||
dataValueCompacted = (dataValueCompacted << 4) | idx;
|
||||
dataArray.writeLong(dataValueCompacted);
|
||||
idxHalfLong = 0;
|
||||
dataItems++;
|
||||
}
|
||||
|
||||
// block light data
|
||||
if (idxHalfByte1 == 0) {
|
||||
blockLightCompacted = block.getLight();
|
||||
idxHalfByte1++;
|
||||
} else {
|
||||
blockLightCompacted = (blockLightCompacted << 4) | block.getLight();
|
||||
blockLight.writeByte(blockLightCompacted);
|
||||
idxHalfByte1 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void addSkyLight(int value) {
|
||||
// sky light data
|
||||
if (idxHalfByte2 == 0) {
|
||||
skyLightCompacted = value;
|
||||
idxHalfByte2++;
|
||||
} else {
|
||||
skyLightCompacted = (skyLightCompacted << 4) | value;
|
||||
skyLight.writeByte(skyLightCompacted);
|
||||
idxHalfByte2 = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void writeToNetStream(final NetOutputStream netOutputStream) {
|
||||
// <Palette>
|
||||
netOutputStream.writeUnsignedByte(4); // Bits Per Block
|
||||
netOutputStream.writeVarInt(palette.size()); // Size of palette
|
||||
palette.forEach(value -> { netOutputStream.writeVarInt(value); return true; }); // Palette
|
||||
// </Palette>
|
||||
// <Data Array>
|
||||
netOutputStream.writeVarInt(dataItems); // Size of Data Array
|
||||
netOutputStream.writeBytes(dataArray.toByteArray()); // Data Array
|
||||
// </Data Array>
|
||||
// <Block Light>
|
||||
netOutputStream.writeBytes(blockLight.toByteArray());
|
||||
// </Block Light>
|
||||
// <Sky Light>
|
||||
netOutputStream.writeBytes(skyLight.toByteArray());
|
||||
// </Sky Light>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user