оптимизирован и исправлен алгоритм сериализации чанка
This commit is contained in:
@@ -6,4 +6,5 @@ dependencies {
|
|||||||
|
|
||||||
/* Components */
|
/* Components */
|
||||||
compile (group: 'com.google.code.gson', name: 'gson', version: '2.8.5')
|
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;
|
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.NoArgsConstructor;
|
||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
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.Chunk;
|
||||||
import mc.core.world.chunk.ChunkSection;
|
import mc.core.world.chunk.ChunkSection;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@@ -80,10 +77,6 @@ public class ChunkDataPacket implements SCPacket {
|
|||||||
private Chunk chunk;
|
private Chunk chunk;
|
||||||
private List<ChunkSection> sectionList;
|
private List<ChunkSection> sectionList;
|
||||||
|
|
||||||
private int serializeBlockState(BlockType blockType) {
|
|
||||||
return (blockType.getId() << 4) | blockType.getMeta();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setChunk(Chunk chunk) {
|
public void setChunk(Chunk chunk) {
|
||||||
this.sectionList = null;
|
this.sectionList = null;
|
||||||
this.chunk = chunk;
|
this.chunk = chunk;
|
||||||
@@ -96,13 +89,18 @@ public class ChunkDataPacket implements SCPacket {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeSelf(NetOutputStream netStream) {
|
public void writeSelf(NetOutputStream netStream) {
|
||||||
|
if (sectionList == null && chunk == null) {
|
||||||
|
log.warn("Empty chunk data!"); //TODO для такого нужна заглушка
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
netStream.writeInt(x); // Chunk X
|
netStream.writeInt(x); // Chunk X
|
||||||
netStream.writeInt(z); // Chunk Y
|
netStream.writeInt(z); // Chunk Y
|
||||||
netStream.writeBoolean(initChunk); // Init Chunk
|
netStream.writeBoolean(initChunk); // Init Chunk
|
||||||
|
|
||||||
int maxH = 0;
|
int maxH = 0;
|
||||||
|
int bitMask = 0;
|
||||||
if (sectionList == null && chunk != null) {
|
if (sectionList == null && chunk != null) {
|
||||||
int bitMask = 0;
|
|
||||||
for (int h = 15; h >= 0; h--) {
|
for (int h = 15; h >= 0; h--) {
|
||||||
bitMask = bitMask << 1;
|
bitMask = bitMask << 1;
|
||||||
ChunkSection chunkSection = chunk.getChunkSection(h);
|
ChunkSection chunkSection = chunk.getChunkSection(h);
|
||||||
@@ -113,11 +111,8 @@ public class ChunkDataPacket implements SCPacket {
|
|||||||
bitMask |= 0x00;
|
bitMask |= 0x00;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
netStream.writeVarInt(bitMask); // Primary Bit Mask
|
|
||||||
} else if (sectionList != null && chunk == null) {
|
} else if (sectionList != null && chunk == null) {
|
||||||
sectionList.sort(Comparator.comparingInt(ChunkSection::getY));
|
sectionList.sort(Comparator.comparingInt(ChunkSection::getY));
|
||||||
int bitMask = 0;
|
|
||||||
for (int h = 15, i = 0; h >= 0; h--) {
|
for (int h = 15, i = 0; h >= 0; h--) {
|
||||||
bitMask = bitMask << 1;
|
bitMask = bitMask << 1;
|
||||||
ChunkSection chunkSection = sectionList.get(i);
|
ChunkSection chunkSection = sectionList.get(i);
|
||||||
@@ -128,16 +123,13 @@ public class ChunkDataPacket implements SCPacket {
|
|||||||
bitMask |= 0x00;
|
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();
|
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++) {
|
for (int h = 0; h < maxH; h++) {
|
||||||
ChunkSection chunkSection = null;
|
ChunkSection chunkSection = null;
|
||||||
@@ -152,64 +144,19 @@ public class ChunkDataPacket implements SCPacket {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
final List<Integer> palette = new ArrayList<>();
|
final PalettedChunkSection palettedChunkSection = new PalettedChunkSection();
|
||||||
palette.add(airBlockPalette);
|
palettedChunkSection.addBlockType(BlockType.AIR);
|
||||||
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;
|
|
||||||
|
|
||||||
for (int y = 0; y < 16; y++) {
|
for (int y = 0; y < 16; y++) {
|
||||||
for (int z = 0; z < 16; z++) {
|
for (int z = 0; z < 16; z++) {
|
||||||
for (int x = 0; x < 16; x++) {
|
for (int x = 0; x < 16; x++) {
|
||||||
Block block = chunkSection.getBlock(x, y, z);
|
palettedChunkSection.addBlock(chunkSection.getBlock(x, y, z));
|
||||||
int blockState = serializeBlockState(block.getBlockType());
|
palettedChunkSection.addSkyLight(chunkSection.getSkyLight(x, y, z));
|
||||||
|
|
||||||
int currentIndexPaletteBlock;
|
if (biomeWrite) {
|
||||||
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) {
|
|
||||||
biomes.writeByte(chunkSection.getBiome(x, z).getId());
|
biomes.writeByte(chunkSection.getBiome(x, z).getId());
|
||||||
if (x == 15 && z == 15) {
|
if (x == 15 && z == 15) {
|
||||||
biomeFinally = true;
|
biomeWrite = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -217,30 +164,109 @@ public class ChunkDataPacket implements SCPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// <Chunk Section>
|
// <Chunk Section>
|
||||||
// <Palette>
|
palettedChunkSection.writeToNetStream(data);
|
||||||
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>
|
|
||||||
// </Chunk Section>
|
// </Chunk Section>
|
||||||
// <Biomes>
|
|
||||||
data.writeBytes(biomes.toByteArray());
|
|
||||||
// </Biomes>
|
|
||||||
}
|
}
|
||||||
|
// <Biomes>
|
||||||
|
data.writeBytes(biomes.toByteArray());
|
||||||
|
// </Biomes>
|
||||||
|
|
||||||
netStream.writeVarInt(data.size()); // Size of Data
|
netStream.writeVarInt(data.size()); // Size of Data
|
||||||
netStream.writeBytes(data.toByteArray()); // Data
|
netStream.writeBytes(data.toByteArray()); // Data
|
||||||
netStream.writeVarInt(0); // Number of block entities
|
netStream.writeVarInt(0); // Number of block entities
|
||||||
/* writeNBT */
|
/* 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