Merge branch 'world-loader-anvil' into proto_1.12.2
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,18 +1,19 @@
|
||||
/*
|
||||
* DmitriyMX <dimon550@gmail.com>
|
||||
* 2018-07-25
|
||||
*/
|
||||
package mc.core.network.proto_1_12_2;
|
||||
|
||||
import com.flowpowered.nbt.Tag;
|
||||
import com.flowpowered.nbt.stream.NBTInputStream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import mc.core.network.NetInputStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
@Slf4j
|
||||
public abstract class NetInputStream_p340 extends NetInputStream {
|
||||
private NBTInputStream nbtInputStream;
|
||||
|
||||
@Override
|
||||
public int readVarInt(AtomicInteger countReadBytes) {
|
||||
int numRead = 0;
|
||||
@@ -59,4 +60,23 @@ public abstract class NetInputStream_p340 extends NetInputStream {
|
||||
public UUID readUUID() {
|
||||
return new UUID(readLong(), readLong());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag<?> readNBT() {
|
||||
if (nbtInputStream == null) {
|
||||
try {
|
||||
nbtInputStream = new NBTInputStream(this, false);
|
||||
} catch (IOException e) {
|
||||
log.error("Create NBT stream", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
return nbtInputStream.readTag();
|
||||
} catch (IOException e) {
|
||||
log.error("Read NBT", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
package mc.core.network.proto_1_12_2;
|
||||
|
||||
import com.flowpowered.nbt.Tag;
|
||||
import com.flowpowered.nbt.stream.NBTOutputStream;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import mc.core.network.NetOutputStream;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
|
||||
@Slf4j
|
||||
public abstract class NetOutputStream_p340 extends NetOutputStream {
|
||||
private NBTOutputStream nbtOutputStream;
|
||||
|
||||
@Override
|
||||
public void writeVarInt(int value) {
|
||||
while ((value & -128) != 0) {
|
||||
@@ -37,4 +42,22 @@ public abstract class NetOutputStream_p340 extends NetOutputStream {
|
||||
writeLong(uuid.getMostSignificantBits());
|
||||
writeLong(uuid.getLeastSignificantBits());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeNBT(Tag<?> tag) {
|
||||
if (nbtOutputStream == null) {
|
||||
try {
|
||||
nbtOutputStream = new NBTOutputStream(this, false);
|
||||
} catch (IOException e) {
|
||||
log.error("Create NBT stream", e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
nbtOutputStream.writeTag(tag);
|
||||
} catch (IOException e) {
|
||||
log.error("Write NBT", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,17 @@
|
||||
/*
|
||||
* DmitriyMX <dimon550@gmail.com>
|
||||
* 2018-07-21
|
||||
*/
|
||||
package mc.core.network.proto_1_12_2.packets;
|
||||
|
||||
import com.flowpowered.nbt.CompoundTag;
|
||||
import gnu.trove.list.TIntList;
|
||||
import gnu.trove.list.array.TIntArrayList;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import mc.core.network.NetOutputStream;
|
||||
import mc.core.network.SCPacket;
|
||||
import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream;
|
||||
import mc.core.utils.NibbleArray;
|
||||
import mc.core.world.block.Block;
|
||||
import mc.core.world.block.BlockLocation;
|
||||
import mc.core.world.block.BlockType;
|
||||
import mc.core.world.chunk.Chunk;
|
||||
import mc.core.world.chunk.ChunkSection;
|
||||
@@ -80,10 +81,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 +93,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 +115,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 +127,15 @@ 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;
|
||||
|
||||
List<CompoundTag> nbtList = new ArrayList<>();
|
||||
|
||||
for (int h = 0; h < maxH; h++) {
|
||||
ChunkSection chunkSection = null;
|
||||
@@ -152,64 +150,30 @@ 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();
|
||||
|
||||
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.getType());
|
||||
|
||||
int currentIndexPaletteBlock;
|
||||
if (!palette.contains(blockState)) {
|
||||
palette.add(blockState);
|
||||
currentIndexPaletteBlock = palette.size()-1;
|
||||
} else {
|
||||
currentIndexPaletteBlock = palette.indexOf(blockState);
|
||||
palettedChunkSection.addBlock(
|
||||
block,
|
||||
chunkSection.getSkyLight(x, y, z)
|
||||
);
|
||||
|
||||
CompoundTag nbt = block.getNBTData();
|
||||
if (nbt != null) {
|
||||
nbtList.add(nbt);
|
||||
}
|
||||
|
||||
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(chunk.getBiome(x, z).getId());
|
||||
if (biomeWrite) {
|
||||
biomes.writeByte(chunk.getBiome(
|
||||
(chunk.getX() << 4) + x,
|
||||
(chunk.getZ() << 4) + z
|
||||
).getId());
|
||||
if (x == 15 && z == 15) {
|
||||
biomeFinally = true;
|
||||
biomeWrite = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -217,30 +181,137 @@ 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 */
|
||||
netStream.writeVarInt(nbtList.size()); // Number of block entities
|
||||
// <NBT>
|
||||
for (CompoundTag compoundTag : nbtList) {
|
||||
netStream.writeNBT(compoundTag);
|
||||
}
|
||||
// </NBT>
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "ChunkDataPacket{" +
|
||||
"x=" + x +
|
||||
", z=" + z +
|
||||
", chunk=" + chunk +
|
||||
'}';
|
||||
}
|
||||
|
||||
private class PalettedChunkSection {
|
||||
private TIntList palette = new TIntArrayList();
|
||||
private byte[] blocks = new byte[4096];
|
||||
private NibbleArray blockLight = new NibbleArray();
|
||||
private NibbleArray skyLight = new NibbleArray();
|
||||
|
||||
private int coordsToIndex(BlockLocation location) {
|
||||
return coordsToIndex(location.getX(), location.getY(), location.getZ());
|
||||
}
|
||||
|
||||
private int coordsToIndex(int x, int y, int z) {
|
||||
return y << 8 | z << 4 | x;
|
||||
}
|
||||
|
||||
private int serializeBlockState(BlockType blockType) {
|
||||
return (blockType.getId() << 4) | blockType.getMeta();
|
||||
}
|
||||
|
||||
byte addBlockType(BlockType blockType) {
|
||||
int blockState = serializeBlockState(blockType);
|
||||
|
||||
int idx = palette.indexOf(blockState);
|
||||
if (idx == -1) {
|
||||
palette.add(blockState);
|
||||
idx = palette.size()-1;
|
||||
}
|
||||
|
||||
return (byte) idx;
|
||||
}
|
||||
|
||||
void addBlock(Block block, int skyLight) {
|
||||
BlockLocation location = new BlockLocation(
|
||||
block.getLocation().getX() - ((block.getLocation().getX() >> 4) << 4),
|
||||
block.getLocation().getY() - ((block.getLocation().getY() >> 4) << 4),
|
||||
block.getLocation().getZ() - ((block.getLocation().getZ() >> 4) << 4)
|
||||
);
|
||||
blocks[coordsToIndex(location)] = addBlockType(block.getType());
|
||||
blockLight.set(location, block.getLight());
|
||||
this.skyLight.set(location, skyLight);
|
||||
}
|
||||
|
||||
void writeToNetStream(final NetOutputStream netOutputStream) {
|
||||
int bitsPerBlock = 4;
|
||||
if (palette.size() > 15) {
|
||||
if (palette.size() <= 31)
|
||||
bitsPerBlock = 5;
|
||||
else if (palette.size() <= 63)
|
||||
bitsPerBlock = 6;
|
||||
else if (palette.size() <= 127)
|
||||
bitsPerBlock = 7;
|
||||
else if (palette.size() <= 255)
|
||||
bitsPerBlock = 8;
|
||||
}
|
||||
|
||||
// <Palette>
|
||||
netOutputStream.writeUnsignedByte(bitsPerBlock); // Bits Per Block
|
||||
netOutputStream.writeVarInt(palette.size()); // Size of palette
|
||||
palette.forEach(value -> { netOutputStream.writeVarInt(value); return true; }); // Palette
|
||||
// </Palette>
|
||||
// <Data Array>
|
||||
final int dataLength = (4096/*16*16*16*/ * bitsPerBlock) / 64/*size of long in bits*/;
|
||||
netOutputStream.writeVarInt(dataLength); // Size of Data Array
|
||||
// <Array>
|
||||
long value = 0;
|
||||
int lastPos = 0;
|
||||
boolean fairy = false;
|
||||
long fairyValue = 0;
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
final int blockNumber = (((y << 4) + z) << 4) + x;
|
||||
final int startLong = ( blockNumber * bitsPerBlock ) / 64;
|
||||
final int startOffset = ( blockNumber * bitsPerBlock ) % 64;
|
||||
final int endLong = ((blockNumber + 1) * bitsPerBlock - 1) / 64;
|
||||
|
||||
final long idxBlockInPalette = blocks[coordsToIndex(x, y, z)];
|
||||
|
||||
if (startLong != lastPos) {
|
||||
netOutputStream.writeLong(value);
|
||||
lastPos = startLong;
|
||||
if (fairy) {
|
||||
value = fairyValue;
|
||||
fairy = false;
|
||||
} else {
|
||||
value = 0;
|
||||
}
|
||||
}
|
||||
value |= (idxBlockInPalette << startOffset);
|
||||
|
||||
if (startLong != endLong) {
|
||||
fairyValue = idxBlockInPalette >> (64 - startOffset);
|
||||
fairy = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
netOutputStream.writeLong(value);
|
||||
// </Array>
|
||||
// </Data Array>
|
||||
// <Block Light>
|
||||
netOutputStream.writeBytes(blockLight.getRawData());
|
||||
// </Block Light>
|
||||
// <Sky Light>
|
||||
netOutputStream.writeBytes(skyLight.getRawData());
|
||||
// </Sky Light>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ public class ByteArrayInputNetStream extends NetInputStream_p340 {
|
||||
|
||||
@Override
|
||||
public boolean readBoolean() {
|
||||
throw new UnsupportedOperationException();
|
||||
return readByte() != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -39,7 +39,7 @@ public class ByteArrayInputNetStream extends NetInputStream_p340 {
|
||||
|
||||
@Override
|
||||
public int readUnsignedByte() {
|
||||
throw new UnsupportedOperationException();
|
||||
return bais.read() & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -8,6 +8,8 @@ import java.util.Random;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
class ByteArrayInputNetStreamTest {
|
||||
private Random random;
|
||||
@@ -17,6 +19,23 @@ class ByteArrayInputNetStreamTest {
|
||||
random = new Random(System.currentTimeMillis());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReadBoolean() {
|
||||
ByteArrayOutputNetStream byteArrayOutputNetStream = new ByteArrayOutputNetStream();
|
||||
byteArrayOutputNetStream.writeBoolean(true);
|
||||
|
||||
ByteArrayInputNetStream byteArrayInputNetStream = new ByteArrayInputNetStream(byteArrayOutputNetStream.toByteArray());
|
||||
|
||||
assertTrue(byteArrayInputNetStream.readBoolean());
|
||||
|
||||
byteArrayOutputNetStream = new ByteArrayOutputNetStream();
|
||||
byteArrayOutputNetStream.writeBoolean(false);
|
||||
|
||||
byteArrayInputNetStream = new ByteArrayInputNetStream(byteArrayOutputNetStream.toByteArray());
|
||||
|
||||
assertFalse(byteArrayInputNetStream.readBoolean());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReadByte() throws IOException {
|
||||
final byte[] bytes = new byte[1];
|
||||
@@ -73,6 +92,23 @@ class ByteArrayInputNetStreamTest {
|
||||
assertEquals(5, r);
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReadUnsignedByte() {
|
||||
ByteArrayOutputNetStream byteArrayOutputNetStream = new ByteArrayOutputNetStream();
|
||||
byteArrayOutputNetStream.writeUnsignedByte(30);
|
||||
|
||||
ByteArrayInputNetStream byteArrayInputNetStream = new ByteArrayInputNetStream(byteArrayOutputNetStream.toByteArray());
|
||||
|
||||
assertEquals(30, byteArrayInputNetStream.readUnsignedByte());
|
||||
|
||||
byteArrayOutputNetStream = new ByteArrayOutputNetStream();
|
||||
byteArrayOutputNetStream.writeUnsignedByte(130);
|
||||
|
||||
byteArrayInputNetStream = new ByteArrayInputNetStream(byteArrayOutputNetStream.toByteArray());
|
||||
|
||||
assertEquals(130, byteArrayInputNetStream.readUnsignedByte());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testReadInt() {
|
||||
final int integerDig = random.nextInt();
|
||||
|
||||
@@ -104,7 +104,7 @@ class ByteArrayOutputNetStreamTest {
|
||||
byteArrayOutputNetStream.writeShort(smallInt);
|
||||
|
||||
assertArrayEquals(new byte[]{ (byte) (smallInt >>> 8),
|
||||
(byte) smallInt },
|
||||
(byte) smallInt },
|
||||
byteArrayOutputNetStream.toByteArray());
|
||||
}
|
||||
|
||||
@@ -116,9 +116,9 @@ class ByteArrayOutputNetStreamTest {
|
||||
byteArrayOutputNetStream.writeInt(integerDig);
|
||||
|
||||
assertArrayEquals(new byte[]{ (byte) ((integerDig >>> 24) & 0xFF),
|
||||
(byte) ((integerDig >>> 16) & 0xFF),
|
||||
(byte) ((integerDig >>> 8) & 0xFF),
|
||||
(byte) (integerDig & 0xFF) },
|
||||
(byte) ((integerDig >>> 16) & 0xFF),
|
||||
(byte) ((integerDig >>> 8) & 0xFF),
|
||||
(byte) (integerDig & 0xFF) },
|
||||
byteArrayOutputNetStream.toByteArray());
|
||||
}
|
||||
|
||||
@@ -130,13 +130,13 @@ class ByteArrayOutputNetStreamTest {
|
||||
byteArrayOutputNetStream.writeLong(longDig);
|
||||
|
||||
assertArrayEquals(new byte[]{ (byte) ((longDig >>> 56) & 0xFF),
|
||||
(byte) ((longDig >>> 48) & 0xFF),
|
||||
(byte) ((longDig >>> 40) & 0xFF),
|
||||
(byte) ((longDig >>> 32) & 0xFF),
|
||||
(byte) ((longDig >>> 24) & 0xFF),
|
||||
(byte) ((longDig >>> 16) & 0xFF),
|
||||
(byte) ((longDig >>> 8) & 0xFF),
|
||||
(byte) (longDig & 0xFF) },
|
||||
(byte) ((longDig >>> 48) & 0xFF),
|
||||
(byte) ((longDig >>> 40) & 0xFF),
|
||||
(byte) ((longDig >>> 32) & 0xFF),
|
||||
(byte) ((longDig >>> 24) & 0xFF),
|
||||
(byte) ((longDig >>> 16) & 0xFF),
|
||||
(byte) ((longDig >>> 8) & 0xFF),
|
||||
(byte) (longDig & 0xFF) },
|
||||
byteArrayOutputNetStream.toByteArray());
|
||||
}
|
||||
|
||||
@@ -149,9 +149,9 @@ class ByteArrayOutputNetStreamTest {
|
||||
final int floatBits = Float.floatToIntBits(floatDig);
|
||||
|
||||
assertArrayEquals(new byte[]{ (byte) ((floatBits >>> 24) & 0xFF),
|
||||
(byte) ((floatBits >>> 16) & 0xFF),
|
||||
(byte) ((floatBits >>> 8) & 0xFF),
|
||||
(byte) (floatBits & 0xFF) },
|
||||
(byte) ((floatBits >>> 16) & 0xFF),
|
||||
(byte) ((floatBits >>> 8) & 0xFF),
|
||||
(byte) (floatBits & 0xFF) },
|
||||
byteArrayOutputNetStream.toByteArray());
|
||||
}
|
||||
|
||||
@@ -164,13 +164,13 @@ class ByteArrayOutputNetStreamTest {
|
||||
final long doubleBits = Double.doubleToLongBits(doubleDig);
|
||||
|
||||
assertArrayEquals(new byte[]{ (byte) ((doubleBits >>> 56) & 0xFF),
|
||||
(byte) ((doubleBits >>> 48) & 0xFF),
|
||||
(byte) ((doubleBits >>> 40) & 0xFF),
|
||||
(byte) ((doubleBits >>> 32) & 0xFF),
|
||||
(byte) ((doubleBits >>> 24) & 0xFF),
|
||||
(byte) ((doubleBits >>> 16) & 0xFF),
|
||||
(byte) ((doubleBits >>> 8) & 0xFF),
|
||||
(byte) (doubleBits & 0xFF) },
|
||||
(byte) ((doubleBits >>> 48) & 0xFF),
|
||||
(byte) ((doubleBits >>> 40) & 0xFF),
|
||||
(byte) ((doubleBits >>> 32) & 0xFF),
|
||||
(byte) ((doubleBits >>> 24) & 0xFF),
|
||||
(byte) ((doubleBits >>> 16) & 0xFF),
|
||||
(byte) ((doubleBits >>> 8) & 0xFF),
|
||||
(byte) (doubleBits & 0xFF) },
|
||||
byteArrayOutputNetStream.toByteArray());
|
||||
}
|
||||
|
||||
@@ -238,22 +238,22 @@ class ByteArrayOutputNetStreamTest {
|
||||
final long leastSignificantBits = uuid.getLeastSignificantBits();
|
||||
|
||||
assertArrayEquals(new byte[]{ (byte) ((mostSignificantBits >>> 56) & 0xFF),
|
||||
(byte) ((mostSignificantBits >>> 48) & 0xFF),
|
||||
(byte) ((mostSignificantBits >>> 40) & 0xFF),
|
||||
(byte) ((mostSignificantBits >>> 32) & 0xFF),
|
||||
(byte) ((mostSignificantBits >>> 24) & 0xFF),
|
||||
(byte) ((mostSignificantBits >>> 16) & 0xFF),
|
||||
(byte) ((mostSignificantBits >>> 8) & 0xFF),
|
||||
(byte) (mostSignificantBits & 0xFF),
|
||||
(byte) ((mostSignificantBits >>> 48) & 0xFF),
|
||||
(byte) ((mostSignificantBits >>> 40) & 0xFF),
|
||||
(byte) ((mostSignificantBits >>> 32) & 0xFF),
|
||||
(byte) ((mostSignificantBits >>> 24) & 0xFF),
|
||||
(byte) ((mostSignificantBits >>> 16) & 0xFF),
|
||||
(byte) ((mostSignificantBits >>> 8) & 0xFF),
|
||||
(byte) (mostSignificantBits & 0xFF),
|
||||
|
||||
(byte) ((leastSignificantBits >>> 56) & 0xFF),
|
||||
(byte) ((leastSignificantBits >>> 48) & 0xFF),
|
||||
(byte) ((leastSignificantBits >>> 40) & 0xFF),
|
||||
(byte) ((leastSignificantBits >>> 32) & 0xFF),
|
||||
(byte) ((leastSignificantBits >>> 24) & 0xFF),
|
||||
(byte) ((leastSignificantBits >>> 16) & 0xFF),
|
||||
(byte) ((leastSignificantBits >>> 8) & 0xFF),
|
||||
(byte) (leastSignificantBits & 0xFF) },
|
||||
(byte) ((leastSignificantBits >>> 56) & 0xFF),
|
||||
(byte) ((leastSignificantBits >>> 48) & 0xFF),
|
||||
(byte) ((leastSignificantBits >>> 40) & 0xFF),
|
||||
(byte) ((leastSignificantBits >>> 32) & 0xFF),
|
||||
(byte) ((leastSignificantBits >>> 24) & 0xFF),
|
||||
(byte) ((leastSignificantBits >>> 16) & 0xFF),
|
||||
(byte) ((leastSignificantBits >>> 8) & 0xFF),
|
||||
(byte) (leastSignificantBits & 0xFF) },
|
||||
byteArrayOutputNetStream.toByteArray());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,312 @@
|
||||
package mc.core.network.proto_1_12_2.packets;
|
||||
|
||||
import com.flowpowered.nbt.*;
|
||||
import javafx.util.Pair;
|
||||
import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream;
|
||||
import mc.core.network.proto_1_12_2.packets.DumbChunkData.DumbChunkSection;
|
||||
import mc.core.world.Biome;
|
||||
import mc.core.world.block.*;
|
||||
import mc.core.world.chunk.Chunk;
|
||||
import mc.core.world.chunk.ChunkSection;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class ChunkDataPacketTest {
|
||||
private static List<Pair<DumbChunkData, DumbChunkData>> listOfParams;
|
||||
|
||||
private static DumbChunkData createExpectedData(String xz) throws IOException {
|
||||
InputStream inputStream = ChunkDataPacketTest.class.getResourceAsStream(String.format("ChunkDataPacket%s.bin", xz));
|
||||
assertNotNull(inputStream);
|
||||
return DumbChunkData.ReadFromNetInputStream(IOUtils.toByteArray(inputStream));
|
||||
}
|
||||
|
||||
private static Block createChestBlock00(BlockType type, int x, int y, int z, int height) {
|
||||
final BlockLocation location = new BlockLocation(x, y, z);
|
||||
|
||||
final CompoundMap compoundMap = new CompoundMap();
|
||||
compoundMap.put(new IntTag("x", x));
|
||||
compoundMap.put(new IntTag("y", (height << 4) + y));
|
||||
compoundMap.put(new IntTag("z", z));
|
||||
compoundMap.put(new StringTag("id", type.getNamedId()));
|
||||
final CompoundTag compoundTag = new CompoundTag("", compoundMap);
|
||||
|
||||
return new AbstractBlock(type) {
|
||||
@Override
|
||||
public BlockLocation getLocation() {
|
||||
return location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompoundTag getNBTData() {
|
||||
return compoundTag;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static ChunkSection createChunkSection00(int height) {
|
||||
final ChunkSection chunkSection = mock(ChunkSection.class);
|
||||
when(chunkSection.getSkyLight(anyInt(), anyInt(), anyInt())).thenReturn(0);
|
||||
when(chunkSection.getY()).thenReturn(height);
|
||||
|
||||
if (height == 0) {
|
||||
when(chunkSection.getBlock(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
final int x = (int) args[0];
|
||||
final int y = (int) args[1];
|
||||
final int z = (int) args[2];
|
||||
|
||||
BlockFactory blockFactory = new BlockFactory();
|
||||
|
||||
if (y == 0) {
|
||||
// @formatter:off
|
||||
if (x == 0 && z == 0) return blockFactory.create(BlockType.STONE, x, y, z);
|
||||
else if (x == 15 && z == 0) return blockFactory.create(BlockType.GRANITE, x, y, z);
|
||||
else if (x == 0 && z == 15) return blockFactory.create(BlockType.POLISHED_GRANITE, x, y, z);
|
||||
else if (x == 15 && z == 15) return blockFactory.create(BlockType.DIORITE, x, y, z);
|
||||
else return blockFactory.create(BlockType.BEDROCK, x, y, z);
|
||||
// @formatter:on
|
||||
} else {
|
||||
return blockFactory.create(BlockType.STONE, x, y, z);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
when(chunkSection.getBlock(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
final int x = (int) args[0];
|
||||
final int y = (int) args[1];
|
||||
final int z = (int) args[2];
|
||||
|
||||
BlockFactory blockFactory = new BlockFactory();
|
||||
|
||||
// @formatter:off
|
||||
if (y == 0) return blockFactory.create(BlockType.DIRT, x, y, z);
|
||||
else if (y == 1) return blockFactory.create(BlockType.GRASS, x, y, z);
|
||||
else if (y == 2) {
|
||||
if ((x == 2 || x == 4 || x == 5) && z == 1)
|
||||
return createChestBlock00(BlockType.CHEST_NORTH, x, y, z, height);
|
||||
else if ((x == 2 || x == 3 || x == 5) && z == 6)
|
||||
return createChestBlock00(BlockType.CHEST_SOUTH, x, y, z, height);
|
||||
else if (x == 1 && (z == 2 || z == 3 || z == 5))
|
||||
return createChestBlock00(BlockType.CHEST_WEST, x, y, z, height);
|
||||
else if (x == 6 && (z == 2 || z == 4 || z == 5))
|
||||
return createChestBlock00(BlockType.CHEST_EAST, x, y, z, height);
|
||||
else
|
||||
return blockFactory.create(BlockType.AIR, x, y, z);
|
||||
}
|
||||
else return blockFactory.create(BlockType.AIR, x, y, z);
|
||||
// @formatter:on
|
||||
});
|
||||
}
|
||||
|
||||
return chunkSection;
|
||||
}
|
||||
|
||||
private static Chunk createMockChunk00() {
|
||||
final ChunkSection chunkSection0 = createChunkSection00(0);
|
||||
final ChunkSection chunkSection1 = createChunkSection00(1);
|
||||
|
||||
final Chunk chunk = mock(Chunk.class);
|
||||
when(chunk.getX()).thenReturn(0);
|
||||
when(chunk.getZ()).thenReturn(0);
|
||||
when(chunk.getBiome(anyInt(), anyInt())).thenReturn(Biome.PLAINS);
|
||||
when(chunk.getChunkSection(0)).thenReturn(chunkSection0);
|
||||
when(chunk.getChunkSection(1)).thenReturn(chunkSection1);
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private static ChunkSection createChunkSection01() {
|
||||
final ChunkSection chunkSection = mock(ChunkSection.class);
|
||||
when(chunkSection.getSkyLight(anyInt(), anyInt(), anyInt())).thenReturn(0);
|
||||
when(chunkSection.getY()).thenReturn(0);
|
||||
|
||||
final List<BlockType> types = Arrays.asList(
|
||||
BlockType.CLAY,
|
||||
BlockType.ORE_REDSTONE,
|
||||
BlockType.ORE_DIAMOND,
|
||||
BlockType.OBSIDIAN,
|
||||
BlockType.STONE_MOSS,
|
||||
BlockType.SANDSTONE,
|
||||
BlockType.ORE_LAPIS,
|
||||
BlockType.WOOD_JUNGLE,
|
||||
BlockType.WOOD_BIRCH,
|
||||
BlockType.WOOD_SPRUCE,
|
||||
BlockType.WOOD_OAK,
|
||||
BlockType.ORE_COAL,
|
||||
BlockType.ORE_IRON,
|
||||
BlockType.ORE_GOLD,
|
||||
BlockType.GRAVEL,
|
||||
BlockType.SAND
|
||||
);
|
||||
|
||||
when(chunkSection.getBlock(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
final int x = (int) args[0];
|
||||
final int y = (int) args[1];
|
||||
final int z = (int) args[2];
|
||||
|
||||
BlockFactory blockFactory = new BlockFactory();
|
||||
|
||||
if (y == 0) {
|
||||
// @formatter:off
|
||||
if (x == 0 && z == 0) return blockFactory.create(BlockType.STONE, x, y, z);
|
||||
else if (x == 15 && z == 0) return blockFactory.create(BlockType.GRANITE, x, y, z);
|
||||
else if (x == 0 && z == 15) return blockFactory.create(BlockType.POLISHED_GRANITE, x, y, z);
|
||||
else if (x == 15 && z == 15) return blockFactory.create(BlockType.DIORITE, x, y, z);
|
||||
else return blockFactory.create(BlockType.BEDROCK, x, y, z);
|
||||
// @formatter:on
|
||||
} else if (y == 1) {
|
||||
return blockFactory.create(types.get(x), x, y, z);
|
||||
} else {
|
||||
return blockFactory.create(BlockType.AIR, x, y, z);
|
||||
}
|
||||
});
|
||||
|
||||
return chunkSection;
|
||||
}
|
||||
|
||||
private static Chunk createMockChunk01() {
|
||||
final ChunkSection chunkSection0 = createChunkSection01();
|
||||
|
||||
final Chunk chunk = mock(Chunk.class);
|
||||
when(chunk.getX()).thenReturn(0);
|
||||
when(chunk.getZ()).thenReturn(1);
|
||||
when(chunk.getBiome(anyInt(), anyInt())).thenReturn(Biome.PLAINS);
|
||||
when(chunk.getChunkSection(0)).thenReturn(chunkSection0);
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private static void verifyMock(Chunk chunk) {
|
||||
verify(chunk, atLeast(1)).getX();
|
||||
verify(chunk, atLeast(1)).getZ();
|
||||
verify(chunk, times(256)).getBiome(anyInt(), anyInt());
|
||||
verify(chunk, atLeast(2)).getChunkSection(anyInt());
|
||||
}
|
||||
|
||||
private static DumbChunkData createActualData(Chunk chunk) {
|
||||
ChunkDataPacket packet = new ChunkDataPacket();
|
||||
packet.setX(chunk.getX());
|
||||
packet.setZ(chunk.getZ());
|
||||
packet.setChunk(chunk);
|
||||
packet.setInitChunk(true);
|
||||
|
||||
ByteArrayOutputNetStream netStream = new ByteArrayOutputNetStream();
|
||||
packet.writeSelf(netStream);
|
||||
|
||||
verifyMock(chunk);
|
||||
|
||||
return DumbChunkData.ReadFromNetInputStream(netStream.toByteArray());
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
static void beforeClassTest() throws IOException {
|
||||
listOfParams = Arrays.asList(
|
||||
new Pair<>(createExpectedData("00"), createActualData(createMockChunk00())),
|
||||
new Pair<>(createExpectedData("01"), createActualData(createMockChunk01()))
|
||||
);
|
||||
}
|
||||
|
||||
private static Stream<Arguments> streamArguments() {
|
||||
return listOfParams.stream().map(pair -> Arguments.of(pair.getKey(), pair.getValue()));
|
||||
}
|
||||
|
||||
@DisplayName("testGeneral")
|
||||
@ParameterizedTest(name = "[{index}] {0}")
|
||||
@MethodSource("streamArguments")
|
||||
void testGeneral(DumbChunkData expected, DumbChunkData actual) {
|
||||
assertEquals(expected.getX(), actual.getX(), "X coord not equals");
|
||||
assertEquals(expected.getZ(), actual.getZ(), "Z coord not equals");
|
||||
assertEquals(expected.isInitChunk(), actual.isInitChunk(), "Flag init chunk not equals");
|
||||
assertEquals(expected.getBitMask(), actual.getBitMask(), "BitMask not equals");
|
||||
assertArrayEquals(expected.getBiomes(), actual.getBiomes(), "Biomes not equals");
|
||||
}
|
||||
|
||||
@DisplayName("testNBT")
|
||||
@ParameterizedTest(name = "[{index}] {0}")
|
||||
@MethodSource("streamArguments")
|
||||
void testNBT(DumbChunkData expected, DumbChunkData actual) {
|
||||
assertEquals(expected.getNumberNBT(), actual.getNumberNBT());
|
||||
assertEquals(expected.getNbt().size(), actual.getNbt().size());
|
||||
|
||||
for (Tag<?> tag : actual.getNbt()) {
|
||||
assertTrue(expected.getNbt().contains(tag));
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("testData (disabled light test)")
|
||||
@ParameterizedTest(name = "[{index}] {0}")
|
||||
@MethodSource("streamArguments")
|
||||
void testData(DumbChunkData expected, DumbChunkData actual) {
|
||||
assertEquals(expected.getData().length, actual.getData().length);
|
||||
|
||||
for (int numberSection = 0; numberSection < expected.getData().length; numberSection++) {
|
||||
final DumbChunkSection expectedSection = expected.getData()[numberSection];
|
||||
final DumbChunkSection actualSection = actual.getData()[numberSection];
|
||||
|
||||
// Palette
|
||||
testPalette(expectedSection, actualSection, numberSection);
|
||||
|
||||
// Data
|
||||
testDataBlock(expectedSection, actualSection, numberSection);
|
||||
|
||||
// Block and Sky light
|
||||
// DISABLE //
|
||||
//testLight(expectedSection, actualSection, numberSection);
|
||||
}
|
||||
}
|
||||
|
||||
private void testPalette(DumbChunkSection expected, DumbChunkSection actual, int numberSection) {
|
||||
assertEquals(expected.getBitsPerBlock(), actual.getBitsPerBlock());
|
||||
|
||||
if (expected.getPalette().size() > actual.getPalette().size()) {
|
||||
for (int j = 0; j < actual.getPalette().size(); j++) {
|
||||
assertTrue(expected.getPalette().contains(
|
||||
actual.getPalette().get(j)
|
||||
), String.format("[%d] Palette not contains %s", numberSection, actual.getPalette().get(j)));
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < expected.getPalette().size(); j++) {
|
||||
assertTrue(actual.getPalette().contains(
|
||||
expected.getPalette().get(j)
|
||||
), String.format("[%d] Palette not contains %s", numberSection, actual.getPalette().get(j)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void testDataBlock(DumbChunkSection expected, DumbChunkSection actual, int numberSection) {
|
||||
assertEquals(expected.getData().size(), actual.getData().size());
|
||||
|
||||
for (int j = 0; j < expected.getData().size(); j++) {
|
||||
assertEquals(
|
||||
expected.getData().get(j),
|
||||
actual.getData().get(j),
|
||||
String.format("[%d] Data (blocks)", numberSection)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void testLight(DumbChunkSection expected, DumbChunkSection actual, int numberSection) {
|
||||
// Block light
|
||||
assertArrayEquals(expected.getBlockLight(), actual.getBlockLight(),
|
||||
String.format("[%d] Block light", numberSection));
|
||||
|
||||
// Sky light
|
||||
assertArrayEquals(expected.getSkyLight(), actual.getSkyLight(),
|
||||
String.format("[%d] Sky light", numberSection));
|
||||
}
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
package mc.core.network.proto_1_12_2.packets;
|
||||
|
||||
import com.google.common.io.ByteStreams;
|
||||
import mc.core.network.proto_1_12_2.ByteArrayOutputNetStream;
|
||||
import mc.core.world.Biome;
|
||||
import mc.core.world.World;
|
||||
import mc.core.world.WorldType;
|
||||
import mc.core.world.block.BlockFactory;
|
||||
import mc.core.world.block.BlockType;
|
||||
import mc.core.world.chunk.Chunk;
|
||||
import mc.core.world.chunk.ChunkSection;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertArrayEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class ChunkdataPacketTest {
|
||||
private static byte[] expectedPacketData;
|
||||
private World world;
|
||||
|
||||
@BeforeAll
|
||||
static void beforeClassTest() throws IOException {
|
||||
InputStream inputStream = ChunkdataPacketTest.class.getResourceAsStream("ChunkDataPacket.bin");
|
||||
expectedPacketData = ByteStreams.toByteArray(inputStream);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void prepareWorld() {
|
||||
final ChunkSection chunkSection = mock(ChunkSection.class);
|
||||
when(chunkSection.getSkyLight(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
||||
int y = (int)invocation.getArguments()[1];
|
||||
|
||||
if (y <= 3) return 0;
|
||||
else return 15;
|
||||
});
|
||||
when(chunkSection.getBlock(anyInt(), anyInt(), anyInt())).thenAnswer(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
int x = (int) args[0];
|
||||
int y = (int) args[1];
|
||||
int z = (int) args[2];
|
||||
|
||||
BlockFactory blockFactory = new BlockFactory();
|
||||
|
||||
if (y == 0) return blockFactory.create(BlockType.BEDROCK, x, y, z);
|
||||
else if (y >= 1 && y <= 2) return blockFactory.create(BlockType.DIRT, x, y, z);
|
||||
else if (y == 3) return blockFactory.create(BlockType.GRASS, x, y, z);
|
||||
else return blockFactory.create(BlockType.AIR, x, y, z);
|
||||
});
|
||||
|
||||
world = mock(World.class);
|
||||
when(world.getType()).thenReturn(WorldType.FLAT);
|
||||
when(world.getChunk(anyInt(), anyInt())).thenAnswer(invocation -> {
|
||||
Object[] args = invocation.getArguments();
|
||||
|
||||
Chunk chunk = mock(Chunk.class);
|
||||
when(chunk.getX()).thenReturn((int) args[0]);
|
||||
when(chunk.getZ()).thenReturn((int) args[1]);
|
||||
when(chunk.getBiome(anyInt(), anyInt())).thenReturn(Biome.PLAINS);
|
||||
when(chunk.getChunkSection(anyInt())).thenAnswer(invocation1 -> {
|
||||
int height = (int)invocation1.getArguments()[0];
|
||||
|
||||
if (height < 1) return chunkSection;
|
||||
else return null;
|
||||
});
|
||||
|
||||
return chunk;
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void writePacket() {
|
||||
ChunkDataPacket packet = new ChunkDataPacket();
|
||||
packet.setX(0);
|
||||
packet.setZ(0);
|
||||
packet.setChunk(world.getChunk(0, 0));
|
||||
packet.setInitChunk(true);
|
||||
|
||||
ByteArrayOutputNetStream netStream = new ByteArrayOutputNetStream();
|
||||
packet.writeSelf(netStream);
|
||||
byte[] actualPacketData = netStream.toByteArray();
|
||||
|
||||
assertEquals(expectedPacketData.length, actualPacketData.length);
|
||||
assertArrayEquals(expectedPacketData, actualPacketData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,133 @@
|
||||
package mc.core.network.proto_1_12_2.packets;
|
||||
|
||||
import com.flowpowered.nbt.Tag;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import mc.core.network.proto_1_12_2.ByteArrayInputNetStream;
|
||||
import mc.core.world.block.BlockType;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
class DumbChunkData {
|
||||
private int x;
|
||||
private int z;
|
||||
private boolean initChunk;
|
||||
private int bitMask;
|
||||
|
||||
private int sizeOfData;
|
||||
private DumbChunkSection[] data;
|
||||
private byte[] biomes;
|
||||
|
||||
private int numberNBT;
|
||||
private List<Tag<?>> nbt;
|
||||
|
||||
private static BlockType deserializeBlockState(int blockState) {
|
||||
return BlockType.getByIdMeta(blockState >> 4, blockState & 0x0F);
|
||||
}
|
||||
|
||||
static DumbChunkData ReadFromNetInputStream(byte[] bytes) {
|
||||
ByteArrayInputNetStream netStream = new ByteArrayInputNetStream(bytes);
|
||||
|
||||
DumbChunkData dumbChunkData = new DumbChunkData();
|
||||
|
||||
dumbChunkData.x = netStream.readInt();
|
||||
dumbChunkData.z = netStream.readInt();
|
||||
dumbChunkData.initChunk = netStream.readBoolean();
|
||||
|
||||
dumbChunkData.bitMask = netStream.readVarInt();
|
||||
int countOfSections = 0;
|
||||
for (int shift = 0; shift < 8; shift++) {
|
||||
countOfSections += ((dumbChunkData.bitMask >> shift) & 0x01) > 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
dumbChunkData.sizeOfData = netStream.readVarInt();
|
||||
|
||||
dumbChunkData.data = new DumbChunkSection[countOfSections];
|
||||
for (int c = 0; c < countOfSections; c++) {
|
||||
DumbChunkSection dumbChunkSection = new DumbChunkSection();
|
||||
|
||||
dumbChunkSection.bitsPerBlock = netStream.readUnsignedByte();
|
||||
int sizePalette = netStream.readVarInt();
|
||||
dumbChunkSection.palette = new ArrayList<>(sizePalette);
|
||||
for (int i = 0; i < sizePalette; i++) {
|
||||
dumbChunkSection.palette.add(deserializeBlockState(netStream.readVarInt()));
|
||||
}
|
||||
|
||||
final byte[] rawData = new byte[netStream.readVarInt() * 8];
|
||||
netStream.readBytes(rawData);
|
||||
LongBuffer data = ByteBuffer.wrap(rawData).asLongBuffer();
|
||||
|
||||
final int bitMask = (1 << dumbChunkSection.bitsPerBlock) - 1;
|
||||
dumbChunkSection.data = new ArrayList<>(4096);
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
for (int x = 0; x < 16; x++) {
|
||||
final int blockNumber = (((y << 4) + z) << 4) + x;
|
||||
final int startLong = ( blockNumber * dumbChunkSection.bitsPerBlock ) / 64;
|
||||
final int startOffset = ( blockNumber * dumbChunkSection.bitsPerBlock ) % 64;
|
||||
final int endLong = ((blockNumber + 1) * dumbChunkSection.bitsPerBlock - 1) / 64;
|
||||
|
||||
int idxBlock;
|
||||
if (startLong == endLong) {
|
||||
idxBlock = (int)(data.get(startLong) >> startOffset);
|
||||
} else {
|
||||
int endOffset = 64 - startOffset;
|
||||
long mask = (1 << endOffset) - 1;
|
||||
idxBlock = (int)(((data.get(startLong) >> startOffset) & mask) | data.get(endLong) << endOffset);
|
||||
}
|
||||
|
||||
dumbChunkSection.data.add(dumbChunkSection.palette.get(idxBlock & bitMask));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
dumbChunkSection.blockLight = new byte[2048];
|
||||
netStream.readBytes(dumbChunkSection.blockLight);
|
||||
dumbChunkSection.skyLight = new byte[2048];
|
||||
netStream.readBytes(dumbChunkSection.skyLight);
|
||||
|
||||
dumbChunkData.data[c] = dumbChunkSection;
|
||||
}
|
||||
|
||||
dumbChunkData.biomes = new byte[256];
|
||||
netStream.readBytes(dumbChunkData.biomes);
|
||||
|
||||
dumbChunkData.numberNBT = netStream.readVarInt();
|
||||
if (dumbChunkData.numberNBT > 0) {
|
||||
dumbChunkData.nbt = new ArrayList<>(dumbChunkData.numberNBT);
|
||||
for (int i = 0; i < dumbChunkData.numberNBT; i++) {
|
||||
dumbChunkData.nbt.add(netStream.readNBT());
|
||||
}
|
||||
} else {
|
||||
dumbChunkData.nbt = Collections.emptyList();
|
||||
}
|
||||
|
||||
return dumbChunkData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DumbChunkData{" +
|
||||
"x=" + x +
|
||||
", z=" + z +
|
||||
'}';
|
||||
}
|
||||
|
||||
@NoArgsConstructor(access = AccessLevel.PRIVATE)
|
||||
@Getter
|
||||
static class DumbChunkSection {
|
||||
private int bitsPerBlock;
|
||||
private List<BlockType> palette;
|
||||
|
||||
private List<BlockType> data;
|
||||
private byte[] blockLight;
|
||||
private byte[] skyLight;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user