Archived
0

Merge branch 'world-loader-anvil' into proto_1.12.2

This commit is contained in:
2019-01-29 11:43:51 +03:00
51 changed files with 2811 additions and 287 deletions

View File

@@ -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

View File

@@ -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();

View File

@@ -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());
}
}

View File

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

View File

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

View File

@@ -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;
}
}