Archived
0

оптимизирован и исправлен алгоритм сериализации чанка

This commit is contained in:
2018-10-28 20:11:52 +03:00
parent ab6501fbfd
commit 2e2fc13615
2 changed files with 116 additions and 89 deletions

View File

@@ -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')
}

View File

@@ -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;
int bitMask = 0;
if (sectionList == null && chunk != null) {
int bitMask = 0;
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>
}
// <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>
}
}
}