улучшен тест ChunkDataPacket
This commit is contained in:
@@ -147,7 +147,6 @@ public class ChunkDataPacket implements SCPacket {
|
||||
}
|
||||
|
||||
final PalettedChunkSection palettedChunkSection = new PalettedChunkSection();
|
||||
palettedChunkSection.addBlockType(BlockType.AIR);
|
||||
|
||||
for (int y = 0; y < 16; y++) {
|
||||
for (int z = 0; z < 16; z++) {
|
||||
@@ -158,7 +157,7 @@ public class ChunkDataPacket implements SCPacket {
|
||||
);
|
||||
|
||||
if (biomeWrite) {
|
||||
biomes.writeByte(chunkSection.getBiomeLocal(x, z).getId());
|
||||
biomes.writeByte(chunk.getBiomeLocal(x, z).getId());
|
||||
if (x == 15 && z == 15) {
|
||||
biomeWrite = false;
|
||||
}
|
||||
@@ -246,7 +245,7 @@ public class ChunkDataPacket implements SCPacket {
|
||||
palette.forEach(value -> { netOutputStream.writeVarInt(value); return true; }); // Palette
|
||||
// </Palette>
|
||||
// <Data Array>
|
||||
final int dataLength = (4096/*16*16*16*/ * bitsPerBlock) / 64;
|
||||
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;
|
||||
|
||||
@@ -3,17 +3,18 @@ package mc.core.network.proto_1_12_2.packets;
|
||||
import mc.core.network.proto_1_12_2.NetInputStream_p340;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
public class ByteArrayInputNetStream extends NetInputStream_p340 {
|
||||
private ByteArrayInputStream bais;
|
||||
|
||||
public ByteArrayInputNetStream(byte[] buff) {
|
||||
ByteArrayInputNetStream(byte[] buff) {
|
||||
bais = new ByteArrayInputStream(buff);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean readBoolean() {
|
||||
return false;
|
||||
return readByte() != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -23,11 +24,19 @@ public class ByteArrayInputNetStream extends NetInputStream_p340 {
|
||||
|
||||
@Override
|
||||
public void readBytes(byte[] buffer) {
|
||||
try {
|
||||
int read = bais.read(buffer);
|
||||
if (read < buffer.length) {
|
||||
throw new IOException("not enough data");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int readUnsignedByte() {
|
||||
return 0;
|
||||
return bais.read() & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,7 +56,7 @@ public class ByteArrayInputNetStream extends NetInputStream_p340 {
|
||||
int ch3 = bais.read();
|
||||
int ch4 = bais.read();
|
||||
if ((ch1 | ch2 | ch3 | ch4) < 0) return 0;
|
||||
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4 << 0));
|
||||
return ((ch1 << 24) + (ch2 << 16) + (ch3 << 8) + (ch4));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -2,42 +2,77 @@ package mc.core.network.proto_1_12_2.packets;
|
||||
|
||||
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.apache.commons.io.IOUtils;
|
||||
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.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.Matchers.anyInt;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
class ChunkDataPacketTest {
|
||||
private static byte[] expectedPacketData;
|
||||
private World world;
|
||||
private static DumbChunkData expectedDumbChunkData;
|
||||
private static DumbChunkData actualDumbChunkData;
|
||||
|
||||
private static void setupExpectedData() throws IOException {
|
||||
InputStream inputStream = ChunkDataPacketTest.class.getResourceAsStream("ChunkDataPacket.bin");
|
||||
assertNotNull(inputStream);
|
||||
expectedDumbChunkData = DumbChunkData.ReadFromNetInputStream(IOUtils.toByteArray(inputStream));
|
||||
}
|
||||
|
||||
private static Chunk createMockChunk() {
|
||||
final ChunkSection chunkSection0 = createChunkSection(0);
|
||||
final ChunkSection chunkSection1 = createChunkSection(1);
|
||||
|
||||
final Chunk chunk = mock(Chunk.class);
|
||||
when(chunk.getX()).thenReturn(0);
|
||||
when(chunk.getZ()).thenReturn(0);
|
||||
when(chunk.getBiomeLocal(anyInt(), anyInt())).thenReturn(Biome.PLAINS);
|
||||
when(chunk.getChunkSection(0)).thenReturn(chunkSection0);
|
||||
when(chunk.getChunkSection(1)).thenReturn(chunkSection1);
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
private static void verifyMock(Chunk chunk) {
|
||||
verify(chunk).getX();
|
||||
verify(chunk).getZ();
|
||||
verify(chunk, times(256)).getBiomeLocal(anyInt(), anyInt());
|
||||
verify(chunk, atLeast(2)).getChunkSection(anyInt());
|
||||
}
|
||||
|
||||
private static void setupActualData() {
|
||||
Chunk chunk = createMockChunk();
|
||||
|
||||
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);
|
||||
|
||||
actualDumbChunkData = DumbChunkData.ReadFromNetInputStream(netStream.toByteArray());
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
static void beforeClassTest() throws IOException {
|
||||
InputStream inputStream = ChunkDataPacketTest.class.getResourceAsStream("ChunkDataPacket.bin");
|
||||
assertNotNull(inputStream);
|
||||
expectedPacketData = IOUtils.toByteArray(inputStream);
|
||||
assertEquals(12571, expectedPacketData.length);
|
||||
setupExpectedData();
|
||||
setupActualData();
|
||||
}
|
||||
|
||||
private ChunkSection createChunkSection(int height) {
|
||||
private static ChunkSection createChunkSection(int height) {
|
||||
final ChunkSection chunkSection = mock(ChunkSection.class);
|
||||
when(chunkSection.getBiomeLocal(anyInt(), anyInt())).thenReturn(Biome.PLAINS);
|
||||
when(chunkSection.getSkyLightLocal(anyInt(), anyInt(), anyInt())).thenReturn(0);
|
||||
when(chunkSection.getY()).thenReturn(height);
|
||||
|
||||
@@ -70,36 +105,63 @@ class ChunkDataPacketTest {
|
||||
return chunkSection;
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
void prepareWorld() {
|
||||
final ChunkSection chunkSection0 = createChunkSection(0);
|
||||
final ChunkSection chunkSection1 = createChunkSection(1);
|
||||
|
||||
final Chunk chunk = mock(Chunk.class);
|
||||
when(chunk.getX()).thenReturn(0);
|
||||
when(chunk.getZ()).thenReturn(0);
|
||||
when(chunk.getBiomeLocal(anyInt(), anyInt())).thenReturn(Biome.PLAINS);
|
||||
when(chunk.getChunkSection(0)).thenReturn(chunkSection0);
|
||||
when(chunk.getChunkSection(1)).thenReturn(chunkSection1);
|
||||
|
||||
world = mock(World.class);
|
||||
when(world.getWorldType()).thenReturn(WorldType.FLAT);
|
||||
when(world.getChunk(0, 0)).thenReturn(chunk);
|
||||
@Test
|
||||
void testGeneral() {
|
||||
assertEquals(expectedDumbChunkData.getX(), actualDumbChunkData.getX());
|
||||
assertEquals(expectedDumbChunkData.getZ(), actualDumbChunkData.getZ());
|
||||
assertEquals(expectedDumbChunkData.isInitChunk(), actualDumbChunkData.isInitChunk());
|
||||
assertEquals(expectedDumbChunkData.getBitMask(), actualDumbChunkData.getBitMask());
|
||||
assertArrayEquals(expectedDumbChunkData.getBiomes(), actualDumbChunkData.getBiomes());
|
||||
}
|
||||
|
||||
@Test
|
||||
void writePacket() {
|
||||
ChunkDataPacket packet = new ChunkDataPacket();
|
||||
packet.setX(0);
|
||||
packet.setZ(0);
|
||||
packet.setChunk(world.getChunk(0, 0));
|
||||
packet.setInitChunk(true);
|
||||
void testNBT() {
|
||||
assertEquals(expectedDumbChunkData.getNumberNBT(), actualDumbChunkData.getNumberNBT());
|
||||
}
|
||||
|
||||
ByteArrayOutputNetStream netStream = new ByteArrayOutputNetStream();
|
||||
packet.writeSelf(netStream);
|
||||
byte[] actualPacketData = netStream.toByteArray();
|
||||
@Test
|
||||
void testData() {
|
||||
assertEquals(expectedDumbChunkData.getData().length, actualDumbChunkData.getData().length);
|
||||
|
||||
assertEquals(expectedPacketData.length, actualPacketData.length);
|
||||
assertArrayEquals(expectedPacketData, actualPacketData);
|
||||
for (int numberSection = 0; numberSection < expectedDumbChunkData.getData().length; numberSection++) {
|
||||
final DumbChunkData.DumbChunkSection expectedDumbChunkSection = expectedDumbChunkData.getData()[numberSection];
|
||||
final DumbChunkData.DumbChunkSection actualDumbChunkSection = actualDumbChunkData.getData()[numberSection];
|
||||
|
||||
// Palette
|
||||
assertEquals(expectedDumbChunkSection.getBitsPerBlock(), actualDumbChunkSection.getBitsPerBlock());
|
||||
|
||||
if (expectedDumbChunkSection.getPalette().size() > actualDumbChunkSection.getPalette().size()) {
|
||||
for (int j = 0; j < actualDumbChunkSection.getPalette().size(); j++) {
|
||||
assertTrue(expectedDumbChunkSection.getPalette().contains(
|
||||
actualDumbChunkSection.getPalette().get(j)
|
||||
), String.format("[%d] Palette not contains %s", numberSection, actualDumbChunkSection.getPalette().get(j)));
|
||||
}
|
||||
} else {
|
||||
for (int j = 0; j < expectedDumbChunkSection.getPalette().size(); j++) {
|
||||
assertTrue(actualDumbChunkSection.getPalette().contains(
|
||||
expectedDumbChunkSection.getPalette().get(j)
|
||||
), String.format("[%d] Palette not contains %s", numberSection, actualDumbChunkSection.getPalette().get(j)));
|
||||
}
|
||||
}
|
||||
|
||||
// Data
|
||||
assertEquals(expectedDumbChunkSection.getData().size(), actualDumbChunkSection.getData().size());
|
||||
|
||||
for (int j = 0; j < expectedDumbChunkSection.getData().size(); j++) {
|
||||
assertEquals(
|
||||
expectedDumbChunkSection.getData().get(j),
|
||||
actualDumbChunkSection.getData().get(j),
|
||||
String.format("[%d] Data (blocks)", numberSection)
|
||||
);
|
||||
}
|
||||
|
||||
// Block light
|
||||
assertArrayEquals(expectedDumbChunkSection.getBlockLight(), actualDumbChunkSection.getBlockLight(),
|
||||
String.format("[%d] Block light", numberSection));
|
||||
|
||||
// Sky light
|
||||
assertArrayEquals(expectedDumbChunkSection.getSkyLight(), actualDumbChunkSection.getSkyLight(),
|
||||
String.format("[%d] Sky light", numberSection));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
package mc.core.network.proto_1_12_2.packets;
|
||||
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import mc.core.world.block.BlockType;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.util.ArrayList;
|
||||
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 static BlockType deserializeBlockState(int blockState) {
|
||||
return BlockType.getByIdMeta((blockState & 0xF0) >> 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;
|
||||
idxBlock = (int)(data.get(startLong) >> startOffset | 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();
|
||||
|
||||
return dumbChunkData;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user