From 14377ca3543ef7c9e5d8d0662d64fe6bd2503672 Mon Sep 17 00:00:00 2001 From: Gerrygames Date: Thu, 25 Oct 2018 13:56:40 +0200 Subject: [PATCH] Use types for ChunkSections --- .../api/minecraft/chunks/Chunk.java | 30 +- .../api/minecraft/chunks/ChunkSection.java | 179 +++++++-- .../types/version/ChunkSectionType1_13.java | 114 ++++++ .../types/version/ChunkSectionType1_8.java | 43 ++ .../types/version/ChunkSectionType1_9.java | 110 ++++++ .../api/type/types/version/Types1_13.java | 3 + .../api/type/types/version/Types1_8.java | 3 + .../api/type/types/version/Types1_9.java | 3 + .../chunks/Chunk1_13.java | 25 -- .../chunks/ChunkSection1_13.java | 311 --------------- .../packets/WorldPackets.java | 2 +- .../types/Chunk1_13Type.java | 12 +- .../chunks/Chunk1_9_3_4.java | 25 -- .../chunks/ChunkSection1_9_3_4.java | 368 ------------------ .../types/Chunk1_9_3_4Type.java | 12 +- .../chunks/Chunk1_9_1_2.java | 24 -- .../chunks/ChunkSection1_9_1_2.java | 360 ----------------- .../types/Chunk1_9_1_2Type.java | 12 +- .../chunks/Chunk1_9to1_8.java | 28 +- .../chunks/ChunkSection1_9to1_8.java | 263 ------------- .../packets/WorldPackets.java | 4 +- ...{ChunkType.java => Chunk1_9to1_8Type.java} | 47 +-- 22 files changed, 477 insertions(+), 1501 deletions(-) create mode 100644 common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_13.java create mode 100644 common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_8.java create mode 100644 common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_9.java delete mode 100644 common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/chunks/Chunk1_13.java delete mode 100644 common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/chunks/ChunkSection1_13.java delete mode 100644 common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_1_2to1_9_3_4/chunks/Chunk1_9_3_4.java delete mode 100644 common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_1_2to1_9_3_4/chunks/ChunkSection1_9_3_4.java delete mode 100644 common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_3to1_9_1_2/chunks/Chunk1_9_1_2.java delete mode 100644 common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_3to1_9_1_2/chunks/ChunkSection1_9_1_2.java delete mode 100644 common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/chunks/ChunkSection1_9to1_8.java rename common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/types/{ChunkType.java => Chunk1_9to1_8Type.java} (75%) diff --git a/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/Chunk.java b/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/Chunk.java index c17ed7f6f..67e2c188b 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/Chunk.java +++ b/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/Chunk.java @@ -1,23 +1,23 @@ package us.myles.ViaVersion.api.minecraft.chunks; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import lombok.AllArgsConstructor; +import lombok.Data; import java.util.List; -public interface Chunk { - int getX(); +@Data +@AllArgsConstructor +public class Chunk { + protected int x; + protected int z; + protected boolean groundUp; + protected int bitmask; + protected ChunkSection[] sections; + protected byte[] biomeData; + protected List blockEntities; - int getZ(); - - ChunkSection[] getSections(); - - boolean isGroundUp(); - - boolean isBiomeData(); - - byte[] getBiomeData(); - - int getBitmask(); - - List getBlockEntities(); + public boolean isBiomeData() { + return biomeData != null; + } } diff --git a/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/ChunkSection.java b/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/ChunkSection.java index 0a6aa0274..2afdbc2cb 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/ChunkSection.java +++ b/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/ChunkSection.java @@ -1,19 +1,32 @@ package us.myles.ViaVersion.api.minecraft.chunks; +import com.google.common.collect.Lists; import io.netty.buffer.ByteBuf; import java.util.List; -public interface ChunkSection { +public class ChunkSection { /** - * Gets a block state id (< 1.13: block_id << 4 | data & 0xF) - * - * @param x Block X - * @param y Block Y - * @param z Block Z - * @return Block raw id + * Size (dimensions) of blocks in a chunks section. */ - int getBlock(int x, int y, int z); + public static final int SIZE = 16 * 16 * 16; // width * depth * height + /** + * Length of the sky and block light nibble arrays. + */ + public static final int LIGHT_LENGTH = 16 * 16 * 16 / 2; // size * size * size / 2 (nibble bit count) + /** + * Length of the block data array. + */ + private final List palette = Lists.newArrayList(); + private final int[] blocks; + private NibbleArray blockLight; + private NibbleArray skyLight; + + public ChunkSection() { + this.blocks = new int[SIZE]; + this.blockLight = new NibbleArray(SIZE); + palette.add(0); // AIR + } /** * Set a block in the chunks @@ -21,53 +34,149 @@ public interface ChunkSection { * @param x Block X * @param y Block Y * @param z Block Z - * @param type The block id + * @param type The type of the block * @param data The data value of the block */ - void setBlock(int x, int y, int z, int type, int data); + public void setBlock(int x, int y, int z, int type, int data) { + setFlatBlock(index(x, y, z), type << 4 | (data & 0xF)); + } + + public void setFlatBlock(int x, int y, int z, int type) { + setFlatBlock(index(x, y, z), type); + } + + public int getBlockId(int x, int y, int z) { + return getFlatBlock(x, y, z) >> 4; + } + + public int getBlockData(int x, int y, int z) { + return getFlatBlock(x, y, z) & 0xF; + } + + public int getFlatBlock(int x, int y, int z) { + int index = blocks[index(x, y, z)]; + return palette.get(index); + } + + public int getFlatBlock(int idx) { + int index = blocks[idx]; + return palette.get(index); + } + + public void setBlock(int idx, int type, int data) { + setFlatBlock(idx, type << 4 | (data & 0xF)); + } + + public void setPaletteIndex(int idx, int index) { + blocks[idx] = index; + } + + public int getPaletteIndex(int idx) { + return blocks[idx]; + } /** - * Set a block state in the chunk + * Set a block in the chunks based on the index * - * @param x Block X - * @param y Block Y - * @param z Block Z - * @param blockState The block state id + * @param idx Index + * @param id The raw or flat id of the block */ - void setFlatBlock(int x, int y, int z, int blockState); + public void setFlatBlock(int idx, int id) { + int index = palette.indexOf(id); + if (index == -1) { + index = palette.size(); + palette.add(id); + } + + blocks[idx] = index; + } /** - * Gets a block id (without data) - * /!\ YOU SHOULD NOT USE THIS ON 1.13 + * Set the block light array * - * @param x Block X - * @param y Block Y - * @param z Block Z - * @return Block id (without data) + * @param data The value to set the block light to */ - int getBlockId(int x, int y, int z); + public void setBlockLight(byte[] data) { + if (data.length != LIGHT_LENGTH) throw new IllegalArgumentException("Data length != " + LIGHT_LENGTH); + if (this.blockLight == null) { + this.blockLight = new NibbleArray(data); + } else { + this.blockLight.setHandle(data); + } + } /** - * Write the blocks in < 1.13 format to a buffer. + * Set the sky light array * - * @param output The buffer to write to. - * @throws Exception Throws if it failed to write. + * @param data The value to set the sky light to */ - void writeBlocks(ByteBuf output) throws Exception; + public void setSkyLight(byte[] data) { + if (data.length != LIGHT_LENGTH) throw new IllegalArgumentException("Data length != " + LIGHT_LENGTH); + if (this.skyLight == null) { + this.skyLight = new NibbleArray(data); + } else { + this.skyLight.setHandle(data); + } + } + + public byte[] getBlockLight() { + return blockLight == null ? null : blockLight.getHandle(); + } + + public byte[] getSkyLight() { + return skyLight == null ? null : skyLight.getHandle(); + } + + public void readBlockLight(ByteBuf input) { + if (this.blockLight == null) { + this.blockLight = new NibbleArray(LIGHT_LENGTH * 2); + } + input.readBytes(this.blockLight.getHandle()); + } + + public void readSkyLight(ByteBuf input) { + if (this.skyLight == null) { + this.skyLight = new NibbleArray(LIGHT_LENGTH * 2); + } + input.readBytes(this.skyLight.getHandle()); + } + + private static int index(int x, int y, int z) { + return y << 8 | z << 4 | x; + } /** - * Write the blocks in 1.13 format to a buffer. + * Write the block light to a buffer * - * @param output The buffer to write to. - * @throws Exception Throws if it failed to write. + * @param output The buffer to write to */ - void writeBlocks1_13(ByteBuf output) throws Exception; + public void writeBlockLight(ByteBuf output) { + output.writeBytes(blockLight.getHandle()); + } - void writeBlockLight(ByteBuf output) throws Exception; + /** + * Write the sky light to a buffer + * + * @param output The buffer to write to + */ + public void writeSkyLight(ByteBuf output) { + output.writeBytes(skyLight.getHandle()); + } - boolean hasSkyLight(); + public List getPalette() { + return palette; + } - void writeSkyLight(ByteBuf output) throws Exception; + /** + * Check if sky light is present + * + * @return True if skylight is present + */ + public boolean hasSkyLight() { + return skyLight != null; + } - List getPalette(); + public boolean hasBlockLight() { + return blockLight != null; + } } diff --git a/common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_13.java b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_13.java new file mode 100644 index 000000000..ee6b89721 --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_13.java @@ -0,0 +1,114 @@ +package us.myles.ViaVersion.api.type.types.version; + +import io.netty.buffer.ByteBuf; +import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; +import us.myles.ViaVersion.api.type.Type; + +import java.util.List; + +public class ChunkSectionType1_13 extends Type { + + public ChunkSectionType1_13() { + super("Chunk Section Type", ChunkSection.class); + } + + @Override + public ChunkSection read(ByteBuf buffer) throws Exception { + ChunkSection chunkSection = new ChunkSection(); + List palette = chunkSection.getPalette(); + palette.clear(); + + // Reaad bits per block + int bitsPerBlock = buffer.readUnsignedByte(); + long maxEntryValue = (1L << bitsPerBlock) - 1; + + if (bitsPerBlock == 0) { + bitsPerBlock = 14; + } + if (bitsPerBlock < 4) { + bitsPerBlock = 4; + } + if (bitsPerBlock > 8) { + bitsPerBlock = 14; + } + int paletteLength = bitsPerBlock == 14 ? 0 : Type.VAR_INT.read(buffer); + // Read palette + for (int i = 0; i < paletteLength; i++) { + palette.add(Type.VAR_INT.read(buffer)); + } + + // Read blocks + long[] blockData = new long[Type.VAR_INT.read(buffer)]; + if (blockData.length > 0) { + for (int i = 0; i < blockData.length; i++) { + blockData[i] = buffer.readLong(); + } + for (int i = 0; i < ChunkSection.SIZE; i++) { + int bitIndex = i * bitsPerBlock; + int startIndex = bitIndex / 64; + int endIndex = ((i + 1) * bitsPerBlock - 1) / 64; + int startBitSubIndex = bitIndex % 64; + int val; + if (startIndex == endIndex) { + val = (int) (blockData[startIndex] >>> startBitSubIndex & maxEntryValue); + } else { + int endBitSubIndex = 64 - startBitSubIndex; + val = (int) ((blockData[startIndex] >>> startBitSubIndex | blockData[endIndex] << endBitSubIndex) & maxEntryValue); + } + + if (bitsPerBlock == 14) { + chunkSection.setFlatBlock(i, val); + } else { + chunkSection.setPaletteIndex(i, val); + } + } + } + + return chunkSection; + } + + @Override + public void write(ByteBuf buffer, ChunkSection chunkSection) throws Exception { + List palette = chunkSection.getPalette(); + + int bitsPerBlock = 4; + while (palette.size() > 1 << bitsPerBlock) { + bitsPerBlock += 1; + } + + if (bitsPerBlock > 8) { + bitsPerBlock = 14; + } + + long maxEntryValue = (1L << bitsPerBlock) - 1; + buffer.writeByte(bitsPerBlock); + + + // Write pallet (or not) + if (bitsPerBlock != 14) { + Type.VAR_INT.write(buffer, palette.size()); + for (int mappedId : palette) { + Type.VAR_INT.write(buffer, mappedId); + } + } + + int length = (int) Math.ceil(ChunkSection.SIZE * bitsPerBlock / 64.0); + Type.VAR_INT.write(buffer, length); + long[] data = new long[length]; + for (int index = 0; index < ChunkSection.SIZE; index++) { + int value = bitsPerBlock == 14 ? chunkSection.getFlatBlock(index) : chunkSection.getPaletteIndex(index); + int bitIndex = index * bitsPerBlock; + int startIndex = bitIndex / 64; + int endIndex = ((index + 1) * bitsPerBlock - 1) / 64; + int startBitSubIndex = bitIndex % 64; + data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex; + if (startIndex != endIndex) { + int endBitSubIndex = 64 - startBitSubIndex; + data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex; + } + } + for (long l : data) { + buffer.writeLong(l); + } + } +} diff --git a/common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_8.java b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_8.java new file mode 100644 index 000000000..66de27a4a --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_8.java @@ -0,0 +1,43 @@ +package us.myles.ViaVersion.api.type.types.version; + +import io.netty.buffer.ByteBuf; +import sun.reflect.generics.reflectiveObjects.NotImplementedException; +import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; +import us.myles.ViaVersion.api.type.Type; + +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.ShortBuffer; +import java.util.List; + +public class ChunkSectionType1_8 extends Type { + + public ChunkSectionType1_8() { + super("Chunk Section Type", ChunkSection.class); + } + + @Override + public ChunkSection read(ByteBuf buffer) throws Exception { + ChunkSection chunkSection = new ChunkSection(); + List palette = chunkSection.getPalette(); + palette.clear(); + + byte[] blockData = new byte[ChunkSection.SIZE * 2]; + buffer.readBytes(blockData); + ShortBuffer blockBuf = ByteBuffer.wrap(blockData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); + + for (int i = 0; i < ChunkSection.SIZE; i++) { + int mask = blockBuf.get(); + int type = mask >> 4; + int data = mask & 0xF; + chunkSection.setBlock(i, type, data); + } + + return chunkSection; + } + + @Override + public void write(ByteBuf buffer, ChunkSection chunkSection) throws Exception { + throw new NotImplementedException(); + } +} diff --git a/common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_9.java b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_9.java new file mode 100644 index 000000000..98d6b3b4d --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_9.java @@ -0,0 +1,110 @@ +package us.myles.ViaVersion.api.type.types.version; + +import io.netty.buffer.ByteBuf; +import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; +import us.myles.ViaVersion.api.type.Type; + +import java.util.List; + +public class ChunkSectionType1_9 extends Type { + + public ChunkSectionType1_9() { + super("Chunk Section Type", ChunkSection.class); + } + + @Override + public ChunkSection read(ByteBuf buffer) throws Exception { + ChunkSection chunkSection = new ChunkSection(); + List palette = chunkSection.getPalette(); + palette.clear(); + + // Reaad bits per block + int bitsPerBlock = buffer.readUnsignedByte(); + long maxEntryValue = (1L << bitsPerBlock) - 1; + + if (bitsPerBlock == 0) { + bitsPerBlock = 13; + } + if (bitsPerBlock < 4) { + bitsPerBlock = 4; + } + if (bitsPerBlock > 8) { + bitsPerBlock = 13; + } + int paletteLength = Type.VAR_INT.read(buffer); + // Read palette + for (int i = 0; i < paletteLength; i++) { + if (bitsPerBlock != 13) { + palette.add(Type.VAR_INT.read(buffer)); + } else { + Type.VAR_INT.read(buffer); + } + } + + // Read blocks + long[] blockData = new long[Type.VAR_INT.read(buffer)]; + if (blockData.length > 0) { + for (int i = 0; i < blockData.length; i++) { + blockData[i] = buffer.readLong(); + } + for (int i = 0; i < ChunkSection.SIZE; i++) { + int bitIndex = i * bitsPerBlock; + int startIndex = bitIndex / 64; + int endIndex = ((i + 1) * bitsPerBlock - 1) / 64; + int startBitSubIndex = bitIndex % 64; + int val; + if (startIndex == endIndex) { + val = (int) (blockData[startIndex] >>> startBitSubIndex & maxEntryValue); + } else { + int endBitSubIndex = 64 - startBitSubIndex; + val = (int) ((blockData[startIndex] >>> startBitSubIndex | blockData[endIndex] << endBitSubIndex) & maxEntryValue); + } + + if (bitsPerBlock == 13) { + chunkSection.setBlock(i, val >> 4, val & 0xF); + } else { + chunkSection.setPaletteIndex(i, val); + } + } + } + + return chunkSection; + } + + @Override + public void write(ByteBuf buffer, ChunkSection chunkSection) throws Exception { + List palette = chunkSection.getPalette(); + + int bitsPerBlock = 4; + while (palette.size() > 1 << bitsPerBlock) { + bitsPerBlock += 1; + } + long maxEntryValue = (1L << bitsPerBlock) - 1; + buffer.writeByte(bitsPerBlock); + + // Write pallet + Type.VAR_INT.write(buffer, palette.size()); + for (int mappedId : palette) { + Type.VAR_INT.write(buffer, mappedId); + } + + int length = (int) Math.ceil(ChunkSection.SIZE * bitsPerBlock / 64.0); + Type.VAR_INT.write(buffer, length); + long[] data = new long[length]; + for (int index = 0; index < ChunkSection.SIZE; index++) { + int value = chunkSection.getPaletteIndex(index); + int bitIndex = index * bitsPerBlock; + int startIndex = bitIndex / 64; + int endIndex = ((index + 1) * bitsPerBlock - 1) / 64; + int startBitSubIndex = bitIndex % 64; + data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex; + if (startIndex != endIndex) { + int endBitSubIndex = 64 - startBitSubIndex; + data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex; + } + } + for (long l : data) { + buffer.writeLong(l); + } + } +} diff --git a/common/src/main/java/us/myles/ViaVersion/api/type/types/version/Types1_13.java b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/Types1_13.java index 415a0e582..f8781f751 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/type/types/version/Types1_13.java +++ b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/Types1_13.java @@ -1,5 +1,6 @@ package us.myles.ViaVersion.api.type.types.version; +import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; import us.myles.ViaVersion.api.minecraft.metadata.Metadata; import us.myles.ViaVersion.api.type.Type; @@ -15,4 +16,6 @@ public class Types1_13 { * Metadata type for 1.13 */ public static final Type METADATA = new Metadata1_13Type(); + + public static final Type CHUNK_SECTION = new ChunkSectionType1_13(); } diff --git a/common/src/main/java/us/myles/ViaVersion/api/type/types/version/Types1_8.java b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/Types1_8.java index 49ca88fae..f5a3747aa 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/type/types/version/Types1_8.java +++ b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/Types1_8.java @@ -1,5 +1,6 @@ package us.myles.ViaVersion.api.type.types.version; +import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; import us.myles.ViaVersion.api.minecraft.metadata.Metadata; import us.myles.ViaVersion.api.type.Type; @@ -15,4 +16,6 @@ public class Types1_8 { * Metadata type for 1.8 */ public static final Type METADATA = new Metadata1_8Type(); + + public static final Type CHUNK_SECTION = new ChunkSectionType1_8(); } diff --git a/common/src/main/java/us/myles/ViaVersion/api/type/types/version/Types1_9.java b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/Types1_9.java index 2917c4d39..58468b42a 100644 --- a/common/src/main/java/us/myles/ViaVersion/api/type/types/version/Types1_9.java +++ b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/Types1_9.java @@ -1,5 +1,6 @@ package us.myles.ViaVersion.api.type.types.version; +import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; import us.myles.ViaVersion.api.minecraft.metadata.Metadata; import us.myles.ViaVersion.api.type.Type; @@ -15,4 +16,6 @@ public class Types1_9 { * Metadata type for 1.9 */ public static final Type METADATA = new Metadata1_9Type(); + + public static final Type CHUNK_SECTION = new ChunkSectionType1_9(); } diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/chunks/Chunk1_13.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/chunks/Chunk1_13.java deleted file mode 100644 index 92cd1b675..000000000 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/chunks/Chunk1_13.java +++ /dev/null @@ -1,25 +0,0 @@ -package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.chunks; - -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import lombok.AllArgsConstructor; -import lombok.Data; -import us.myles.ViaVersion.api.minecraft.chunks.Chunk; - -import java.util.List; - -@Data -@AllArgsConstructor -public class Chunk1_13 implements Chunk { - private int x; - private int z; - private boolean groundUp; - private int bitmask; - private ChunkSection1_13[] sections; - private byte[] biomeData; - private List blockEntities; - - @Override - public boolean isBiomeData() { - return biomeData != null; - } -} diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/chunks/ChunkSection1_13.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/chunks/ChunkSection1_13.java deleted file mode 100644 index 4361e0d70..000000000 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/chunks/ChunkSection1_13.java +++ /dev/null @@ -1,311 +0,0 @@ -package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.chunks; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; -import us.myles.ViaVersion.api.minecraft.chunks.NibbleArray; -import us.myles.ViaVersion.api.type.Type; - -import java.util.List; - -public class ChunkSection1_13 implements ChunkSection { - /** - * Size (dimensions) of blocks in a chunks section. - */ - public static final int SIZE = 16 * 16 * 16; // width * depth * height - /** - * Length of the sky and block light nibble arrays. - */ - public static final int LIGHT_LENGTH = 16 * 16 * 16 / 2; // size * size * size / 2 (nibble bit count) - /** - * Length of the block data array. - */ - private final List palette = Lists.newArrayList(); - private final int[] blocks; - private final NibbleArray blockLight; - private NibbleArray skyLight; - - public ChunkSection1_13() { - this.blocks = new int[SIZE]; - this.blockLight = new NibbleArray(SIZE); - palette.add(0); // AIR - } - - public void setBlock(int x, int y, int z, int type, int data) { - setBlock(index(x, y, z), type, data); - } - - @Override - public void setFlatBlock(int x, int y, int z, int type) { - int index = palette.indexOf(type); - if (index == -1) { - index = palette.size(); - palette.add(type); - } - - blocks[index(x, y, z)] = index; - } - - public int getBlockId(int x, int y, int z) { - return getBlock(x, y, z) >> 4; - } - - public int getBlock(int x, int y, int z) { - int index = blocks[index(x, y, z)]; - return palette.get(index); - } - - /** - * Set a block in the chunks based on the index - * - * @param idx Index - * @param type The type of the block - * @param data The data value of the block - */ - public void setBlock(int idx, int type, int data) { - int hash = type << 4 | (data & 0xF); - int index = palette.indexOf(hash); - if (index == -1) { - index = palette.size(); - palette.add(hash); - } - - blocks[idx] = index; - } - - /** - * Set the block light array - * - * @param data The value to set the block light to - */ - public void setBlockLight(byte[] data) { - blockLight.setHandle(data); - } - - /** - * Set the sky light array - * - * @param data The value to set the sky light to - */ - public void setSkyLight(byte[] data) { - if (data.length != LIGHT_LENGTH) throw new IllegalArgumentException("Data length != " + LIGHT_LENGTH); - this.skyLight = new NibbleArray(data); - } - - private int index(int x, int y, int z) { - return y << 8 | z << 4 | x; - } - - /** - * Read blocks from input stream. - * This reads all the block related data: - *
    - *
  • Block length/palette type
  • - *
  • Palette
  • - *
  • Block hashes/palette reference
  • - *
- * - * @param input The buffer to read from. - * @throws Exception If it fails to read - */ - public void readBlocks(ByteBuf input) throws Exception { - palette.clear(); - - // Read bits per block - int bitsPerBlock = input.readUnsignedByte(); - long maxEntryValue = (1L << bitsPerBlock) - 1; - - boolean directPalette = false; - - if (bitsPerBlock == 0) { - bitsPerBlock = 14; - } - if (bitsPerBlock < 4) { - bitsPerBlock = 4; - } - if (bitsPerBlock >= 9) { - directPalette = true; - bitsPerBlock = 14; - } - - int paletteLength = directPalette ? 0 : Type.VAR_INT.read(input); - // Read palette - for (int i = 0; i < paletteLength; i++) { - palette.add(Type.VAR_INT.read(input)); - } - - // Read blocks - // Long[] blockData = Type.LONG_ARRAY.read(input); - long[] blockData = new long[Type.VAR_INT.read(input)]; - for (int i = 0; i < blockData.length; i++) { - blockData[i] = input.readLong(); - } - - if (blockData.length > 0) { - for (int i = 0; i < blocks.length; i++) { - int bitIndex = i * bitsPerBlock; - int startIndex = bitIndex >> 6; // /64 - int endIndex = ((i + 1) * bitsPerBlock - 1) >> 6; // /64 - int startBitSubIndex = bitIndex & 0x3F; // % 64 - int val; - if (startIndex == endIndex) { - val = (int) (blockData[startIndex] >>> startBitSubIndex & maxEntryValue); - } else { - int endBitSubIndex = 64 - startBitSubIndex; - val = (int) ((blockData[startIndex] >>> startBitSubIndex | blockData[endIndex] << endBitSubIndex) & maxEntryValue); - } - - if (directPalette) { - int type = val >> 4; - int data = val & 0xF; - - setBlock(i, type, data); - } else { - blocks[i] = val; - } - } - } - } - - /** - * Read block light from buffer. - * - * @param input The buffer to read from - */ - public void readBlockLight(ByteBuf input) { - byte[] handle = new byte[LIGHT_LENGTH]; - input.readBytes(handle); - blockLight.setHandle(handle); - } - - /** - * Read sky light from buffer. - * Note: Only sent in overworld! - * - * @param input The buffer to read from - */ - public void readSkyLight(ByteBuf input) { - byte[] handle = new byte[LIGHT_LENGTH]; - input.readBytes(handle); - if (skyLight != null) { - skyLight.setHandle(handle); - return; - } - - this.skyLight = new NibbleArray(handle); - } - - - public void writeBlocks(ByteBuf output) throws Exception { - // Write bits per block - int bitsPerBlock = 4; - while (palette.size() > 1 << bitsPerBlock) { - bitsPerBlock += 1; - } - long maxEntryValue = (1L << bitsPerBlock) - 1; - output.writeByte(bitsPerBlock); - - // Write pallet (or not) - Type.VAR_INT.write(output, palette.size()); - for (int mappedId : palette) { - Type.VAR_INT.write(output, mappedId); - } - - int length = (int) Math.ceil(SIZE * bitsPerBlock / 64.0); - Type.VAR_INT.write(output, length); - long[] data = new long[length]; - for (int index = 0; index < blocks.length; index++) { - int value = blocks[index]; - int bitIndex = index * bitsPerBlock; - int startIndex = bitIndex / 64; - int endIndex = ((index + 1) * bitsPerBlock - 1) / 64; - int startBitSubIndex = bitIndex % 64; - data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex; - if (startIndex != endIndex) { - int endBitSubIndex = 64 - startBitSubIndex; - data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex; - } - } - for (long l : data) { - output.writeLong(l); - } - } - - @Override - public void writeBlocks1_13(ByteBuf output) throws Exception { - // Write bits per block - int bitsPerBlock = 4; - while (palette.size() > 1 << bitsPerBlock) { - bitsPerBlock++; - } - boolean directPalette = false; - if (bitsPerBlock >= 9) { - bitsPerBlock = 14; - directPalette = true; - } - long maxEntryValue = (1L << bitsPerBlock) - 1; - output.writeByte(bitsPerBlock); - - // Write pallet (or not) - if (!directPalette) { - Type.VAR_INT.write(output, palette.size()); - for (int mappedId : palette) { - Type.VAR_INT.write(output, mappedId); - } - } - - int length = (int) Math.ceil(SIZE * bitsPerBlock / 64.0); - Type.VAR_INT.write(output, length); - long[] data = new long[length]; - for (int index = 0; index < blocks.length; index++) { - int value = directPalette ? palette.get(blocks[index]) : blocks[index]; - int bitIndex = index * bitsPerBlock; - int startIndex = bitIndex / 64; - int endIndex = ((index + 1) * bitsPerBlock - 1) / 64; - int startBitSubIndex = bitIndex % 64; - data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex; - if (startIndex != endIndex) { - int endBitSubIndex = 64 - startBitSubIndex; - data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex; - } - } - for (long l : data) { - output.writeLong(l); - } - } - - /** - * Write the block light to a buffer - * - * @param output The buffer to write to - */ - @Override - public void writeBlockLight(ByteBuf output) { - output.writeBytes(blockLight.getHandle()); - } - - /** - * Write the sky light to a buffer - * - * @param output The buffer to write to - */ - @Override - public void writeSkyLight(ByteBuf output) { - output.writeBytes(skyLight.getHandle()); - } - - /** - * Check if sky light is present - * - * @return True if skylight is present - */ - @Override - public boolean hasSkyLight() { - return skyLight != null; - } - - @Override - public List getPalette() { - return palette; - } -} diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/WorldPackets.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/WorldPackets.java index 95146d8ed..f6135bf05 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/WorldPackets.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/packets/WorldPackets.java @@ -254,7 +254,7 @@ public class WorldPackets { for (int x = 0; x < 16; x++) { for (int y = 0; y < 16; y++) { for (int z = 0; z < 16; z++) { - int block = section.getBlock(x, y, z); + int block = section.getFlatBlock(x, y, z); if (storage.isWelcome(block)) { storage.store(new Position( (long) (x + (chunk.getX() << 4)), diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/types/Chunk1_13Type.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/types/Chunk1_13Type.java index c6a63f690..5c6d1e65b 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/types/Chunk1_13Type.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13to1_12_2/types/Chunk1_13Type.java @@ -9,8 +9,7 @@ import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; import us.myles.ViaVersion.api.type.PartialType; import us.myles.ViaVersion.api.type.Type; import us.myles.ViaVersion.api.type.types.minecraft.BaseChunkType; -import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.chunks.Chunk1_13; -import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.chunks.ChunkSection1_13; +import us.myles.ViaVersion.api.type.types.version.Types1_13; import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld; import java.util.ArrayList; @@ -33,7 +32,7 @@ public class Chunk1_13Type extends PartialType { Type.VAR_INT.read(input); BitSet usedSections = new BitSet(16); - ChunkSection1_13[] sections = new ChunkSection1_13[16]; + ChunkSection[] sections = new ChunkSection[16]; // Calculate section count from bitmask for (int i = 0; i < 16; i++) { if ((primaryBitmask & (1 << i)) != 0) { @@ -44,9 +43,8 @@ public class Chunk1_13Type extends PartialType { // Read sections for (int i = 0; i < 16; i++) { if (!usedSections.get(i)) continue; // Section not set - ChunkSection1_13 section = new ChunkSection1_13(); + ChunkSection section = Types1_13.CHUNK_SECTION.read(input); sections[i] = section; - section.readBlocks(input); section.readBlockLight(input); if (world.getEnvironment() == Environment.NORMAL) { section.readSkyLight(input); @@ -71,7 +69,7 @@ public class Chunk1_13Type extends PartialType { } } - return new Chunk1_13(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, nbtData); + return new Chunk(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, nbtData); } @Override @@ -86,7 +84,7 @@ public class Chunk1_13Type extends PartialType { for (int i = 0; i < 16; i++) { ChunkSection section = chunk.getSections()[i]; if (section == null) continue; // Section not set - section.writeBlocks1_13(buf); + Types1_13.CHUNK_SECTION.write(buf, section); section.writeBlockLight(buf); if (!section.hasSkyLight()) continue; // No sky light, we're done here. diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_1_2to1_9_3_4/chunks/Chunk1_9_3_4.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_1_2to1_9_3_4/chunks/Chunk1_9_3_4.java deleted file mode 100644 index 6f899ff61..000000000 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_1_2to1_9_3_4/chunks/Chunk1_9_3_4.java +++ /dev/null @@ -1,25 +0,0 @@ -package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.chunks; - -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import lombok.AllArgsConstructor; -import lombok.Data; -import us.myles.ViaVersion.api.minecraft.chunks.Chunk; - -import java.util.List; - -@Data -@AllArgsConstructor -public class Chunk1_9_3_4 implements Chunk { - private int x; - private int z; - private boolean groundUp; - private int bitmask; - private ChunkSection1_9_3_4[] sections; - private byte[] biomeData; - private List blockEntities; - - @Override - public boolean isBiomeData() { - return biomeData != null; - } -} diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_1_2to1_9_3_4/chunks/ChunkSection1_9_3_4.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_1_2to1_9_3_4/chunks/ChunkSection1_9_3_4.java deleted file mode 100644 index d822c8475..000000000 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_1_2to1_9_3_4/chunks/ChunkSection1_9_3_4.java +++ /dev/null @@ -1,368 +0,0 @@ -package us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.chunks; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; -import us.myles.ViaVersion.api.minecraft.chunks.NibbleArray; -import us.myles.ViaVersion.api.type.Type; - -import java.util.List; - -public class ChunkSection1_9_3_4 implements ChunkSection { - /** - * Size (dimensions) of blocks in a chunks section. - */ - public static final int SIZE = 16 * 16 * 16; // width * depth * height - /** - * Length of the sky and block light nibble arrays. - */ - public static final int LIGHT_LENGTH = 16 * 16 * 16 / 2; // size * size * size / 2 (nibble bit count) - /** - * Length of the block data array. - */ - private final List palette = Lists.newArrayList(); - private final int[] blocks; - private final NibbleArray blockLight; - private NibbleArray skyLight; - - public ChunkSection1_9_3_4() { - this.blocks = new int[SIZE]; - this.blockLight = new NibbleArray(SIZE); - palette.add(0); // AIR - } - - /** - * Set a block in the chunks - * - * @param x Block X - * @param y Block Y - * @param z Block Z - * @param type The type of the block - * @param data The data value of the block - */ - public void setBlock(int x, int y, int z, int type, int data) { - setBlock(index(x, y, z), type, data); - } - - /** - * Set a flat block in the chunks - * - * @param x Block X - * @param y Block Y - * @param z Block Z - * @param type The type of the block - */ - @Override - public void setFlatBlock(int x, int y, int z, int type) { - int index = palette.indexOf(type); - if (index == -1) { - index = palette.size(); - palette.add(type); - } - - blocks[index(x, y, z)] = index; - } - - public int getBlockId(int x, int y, int z) { - return getBlock(x, y, z) >> 4; - } - - public int getBlock(int x, int y, int z) { - int index = blocks[index(x, y, z)]; - return palette.get(index); - } - - /** - * Set a block in the chunks based on the index - * - * @param idx Index - * @param type The type of the block - * @param data The data value of the block - */ - public void setBlock(int idx, int type, int data) { - int hash = type << 4 | (data & 0xF); - int index = palette.indexOf(hash); - if (index == -1) { - index = palette.size(); - palette.add(hash); - } - - blocks[idx] = index; - } - - /** - * Set the block light array - * - * @param data The value to set the block light to - */ - public void setBlockLight(byte[] data) { - blockLight.setHandle(data); - } - - /** - * Set the sky light array - * - * @param data The value to set the sky light to - */ - public void setSkyLight(byte[] data) { - if (data.length != LIGHT_LENGTH) throw new IllegalArgumentException("Data length != " + LIGHT_LENGTH); - this.skyLight = new NibbleArray(data); - } - - private int index(int x, int y, int z) { - return y << 8 | z << 4 | x; - } - - /** - * Read blocks from input stream. - * This reads all the block related data: - *
    - *
  • Block length/palette type
  • - *
  • Palette
  • - *
  • Block hashes/palette reference
  • - *
- * - * @param input The buffer to read from. - * @throws Exception If it fails to read - */ - public void readBlocks(ByteBuf input) throws Exception { - palette.clear(); - - // Read bits per block - int bitsPerBlock = input.readUnsignedByte(); - long maxEntryValue = (1L << bitsPerBlock) - 1; - - if (bitsPerBlock == 0) { - bitsPerBlock = 13; - } - if (bitsPerBlock < 4) { - bitsPerBlock = 4; - } - if (bitsPerBlock > 8) { - bitsPerBlock = 13; - } - int paletteLength = Type.VAR_INT.read(input); - // Read palette - for (int i = 0; i < paletteLength; i++) { - if (bitsPerBlock != 13) { - palette.add(Type.VAR_INT.read(input)); - } else { - Type.VAR_INT.read(input); - } - } - - // Read blocks - //Long[] blockData = Type.LONG_ARRAY.read(input); - long[] blockData = new long[Type.VAR_INT.read(input)]; - for (int i = 0; i < blockData.length; i++) { - blockData[i] = input.readLong(); - } - if (blockData.length > 0) { - for (int i = 0; i < blocks.length; i++) { - int bitIndex = i * bitsPerBlock; - int startIndex = bitIndex / 64; - int endIndex = ((i + 1) * bitsPerBlock - 1) / 64; - int startBitSubIndex = bitIndex % 64; - int val; - if (startIndex == endIndex) { - val = (int) (blockData[startIndex] >>> startBitSubIndex & maxEntryValue); - } else { - int endBitSubIndex = 64 - startBitSubIndex; - val = (int) ((blockData[startIndex] >>> startBitSubIndex | blockData[endIndex] << endBitSubIndex) & maxEntryValue); - } - - if (bitsPerBlock == 13) { - int type = val >> 4; - int data = val & 0xF; - - setBlock(i, type, data); - } else { - blocks[i] = val; - } - } - } - } - - /** - * Read block light from buffer. - * - * @param input The buffer to read from - */ - public void readBlockLight(ByteBuf input) { - byte[] handle = new byte[LIGHT_LENGTH]; - input.readBytes(handle); - blockLight.setHandle(handle); - } - - /** - * Read sky light from buffer. - * Note: Only sent in overworld! - * - * @param input The buffer to read from - */ - public void readSkyLight(ByteBuf input) { - byte[] handle = new byte[LIGHT_LENGTH]; - input.readBytes(handle); - if (skyLight != null) { - skyLight.setHandle(handle); - return; - } - - this.skyLight = new NibbleArray(handle); - } - - /** - * Write the blocks to a buffer. - * - * @param output The buffer to write to. - * @throws Exception Throws if it failed to write. - */ - public void writeBlocks(ByteBuf output) throws Exception { - // Write bits per block - int bitsPerBlock = 4; - while (palette.size() > 1 << bitsPerBlock) { - bitsPerBlock += 1; - } - long maxEntryValue = (1L << bitsPerBlock) - 1; - output.writeByte(bitsPerBlock); - - // Write pallet (or not) - Type.VAR_INT.write(output, palette.size()); - for (int mappedId : palette) { - Type.VAR_INT.write(output, mappedId); - } - - int length = (int) Math.ceil(SIZE * bitsPerBlock / 64.0); - Type.VAR_INT.write(output, length); - long[] data = new long[length]; - for (int index = 0; index < blocks.length; index++) { - int value = blocks[index]; - int bitIndex = index * bitsPerBlock; - int startIndex = bitIndex / 64; - int endIndex = ((index + 1) * bitsPerBlock - 1) / 64; - int startBitSubIndex = bitIndex % 64; - data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex; - if (startIndex != endIndex) { - int endBitSubIndex = 64 - startBitSubIndex; - data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex; - } - } - for (long l : data) { - output.writeLong(l); - } - } - - @Override - public void writeBlocks1_13(ByteBuf output) throws Exception { - // Write bits per block - int bitsPerBlock = 4; - while (palette.size() > 1 << bitsPerBlock) { - bitsPerBlock++; - } - boolean directPalette = false; - if (bitsPerBlock >= 9) { - bitsPerBlock = 14; - directPalette = true; - } - long maxEntryValue = (1L << bitsPerBlock) - 1; - output.writeByte(bitsPerBlock); - - // Write pallet (or not) - if (!directPalette) { - Type.VAR_INT.write(output, palette.size()); - for (int mappedId : palette) { - Type.VAR_INT.write(output, mappedId); - } - } - - int length = (int) Math.ceil(SIZE * bitsPerBlock / 64.0); - Type.VAR_INT.write(output, length); - long[] data = new long[length]; - for (int index = 0; index < blocks.length; index++) { - int value = directPalette ? palette.get(blocks[index]) : blocks[index]; - int bitIndex = index * bitsPerBlock; - int startIndex = bitIndex / 64; - int endIndex = ((index + 1) * bitsPerBlock - 1) / 64; - int startBitSubIndex = bitIndex % 64; - data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex; - if (startIndex != endIndex) { - int endBitSubIndex = 64 - startBitSubIndex; - data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex; - } - } - for (long l : data) { - output.writeLong(l); - } - } - - /** - * Write the block light to a buffer - * - * @param output The buffer to write to - */ - public void writeBlockLight(ByteBuf output) { - output.writeBytes(blockLight.getHandle()); - } - - /** - * Write the sky light to a buffer - * - * @param output The buffer to write to - */ - public void writeSkyLight(ByteBuf output) { - output.writeBytes(skyLight.getHandle()); - } - - /** - * Check if sky light is present - * - * @return True if skylight is present - */ - public boolean hasSkyLight() { - return skyLight != null; - } - - /** - * Get expected size of this chunks section. - * - * @return Amount of bytes sent by this section - * @throws Exception If it failed to calculate bits properly - */ - public int getExpectedSize() throws Exception { - int bitsPerBlock = palette.size() > 255 ? 16 : 8; - int bytes = 1; // bits per block - bytes += paletteBytes(); // palette - bytes += countBytes(bitsPerBlock == 16 ? SIZE * 2 : SIZE); // block data length - bytes += (palette.size() > 255 ? 2 : 1) * SIZE; // block data - bytes += LIGHT_LENGTH; // block light - bytes += hasSkyLight() ? LIGHT_LENGTH : 0; // sky light - return bytes; - } - - private int paletteBytes() throws Exception { - // Count bytes used by pallet - int bytes = countBytes(palette.size()); - for (int mappedId : palette) { - bytes += countBytes(mappedId); - } - return bytes; - } - - private int countBytes(int value) throws Exception { - // Count amount of bytes that would be sent if the value were sent as a VarInt - if ((value & (~0 << 7)) == 0) - return 1; - if ((value & (~0 << 14)) == 0) - return 2; - if ((value & (~0 << 21)) == 0) - return 3; - if ((value & (~0 << 28)) == 0) - return 4; - return 5; - } - - @Override - public List getPalette() { - return palette; - } -} diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_1_2to1_9_3_4/types/Chunk1_9_3_4Type.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_1_2to1_9_3_4/types/Chunk1_9_3_4Type.java index 58f563f05..87e0e86e0 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_1_2to1_9_3_4/types/Chunk1_9_3_4Type.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_1_2to1_9_3_4/types/Chunk1_9_3_4Type.java @@ -9,8 +9,7 @@ import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; import us.myles.ViaVersion.api.type.PartialType; import us.myles.ViaVersion.api.type.Type; import us.myles.ViaVersion.api.type.types.minecraft.BaseChunkType; -import us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.chunks.Chunk1_9_3_4; -import us.myles.ViaVersion.protocols.protocol1_9_1_2to1_9_3_4.chunks.ChunkSection1_9_3_4; +import us.myles.ViaVersion.api.type.types.version.Types1_9; import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld; import java.util.ArrayList; @@ -34,7 +33,7 @@ public class Chunk1_9_3_4Type extends PartialType { Type.VAR_INT.read(input); BitSet usedSections = new BitSet(16); - ChunkSection1_9_3_4[] sections = new ChunkSection1_9_3_4[16]; + ChunkSection[] sections = new ChunkSection[16]; // Calculate section count from bitmask for (int i = 0; i < 16; i++) { if ((primaryBitmask & (1 << i)) != 0) { @@ -45,9 +44,8 @@ public class Chunk1_9_3_4Type extends PartialType { // Read sections for (int i = 0; i < 16; i++) { if (!usedSections.get(i)) continue; // Section not set - ChunkSection1_9_3_4 section = new ChunkSection1_9_3_4(); + ChunkSection section = Types1_9.CHUNK_SECTION.read(input); sections[i] = section; - section.readBlocks(input); section.readBlockLight(input); if (world.getEnvironment() == Environment.NORMAL) { section.readSkyLight(input); @@ -69,7 +67,7 @@ public class Chunk1_9_3_4Type extends PartialType { } } - return new Chunk1_9_3_4(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, nbtData); + return new Chunk(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, nbtData); } @Override @@ -84,7 +82,7 @@ public class Chunk1_9_3_4Type extends PartialType { for (int i = 0; i < 16; i++) { ChunkSection section = chunk.getSections()[i]; if (section == null) continue; // Section not set - section.writeBlocks(buf); + Types1_9.CHUNK_SECTION.write(buf, section); section.writeBlockLight(buf); if (!section.hasSkyLight()) continue; // No sky light, we're done here. diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_3to1_9_1_2/chunks/Chunk1_9_1_2.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_3to1_9_1_2/chunks/Chunk1_9_1_2.java deleted file mode 100644 index 5da9fa4c9..000000000 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_3to1_9_1_2/chunks/Chunk1_9_1_2.java +++ /dev/null @@ -1,24 +0,0 @@ -package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.chunks; - -import com.github.steveice10.opennbt.tag.builtin.CompoundTag; -import lombok.AllArgsConstructor; -import lombok.Data; -import us.myles.ViaVersion.api.minecraft.chunks.Chunk; - -import java.util.List; - -@Data -@AllArgsConstructor -public class Chunk1_9_1_2 implements Chunk { - private int x; - private int z; - private boolean groundUp; - private int bitmask; - private final ChunkSection1_9_1_2[] sections; - private byte[] biomeData; - private List blockEntities; - - public boolean isBiomeData() { - return biomeData != null; - } -} diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_3to1_9_1_2/chunks/ChunkSection1_9_1_2.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_3to1_9_1_2/chunks/ChunkSection1_9_1_2.java deleted file mode 100644 index c0c383b4f..000000000 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_3to1_9_1_2/chunks/ChunkSection1_9_1_2.java +++ /dev/null @@ -1,360 +0,0 @@ -package us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.chunks; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; -import us.myles.ViaVersion.api.minecraft.chunks.NibbleArray; -import us.myles.ViaVersion.api.type.Type; - -import java.util.List; - -public class ChunkSection1_9_1_2 implements ChunkSection { - /** - * Size (dimensions) of blocks in a chunks section. - */ - public static final int SIZE = 16 * 16 * 16; // width * depth * height - /** - * Length of the sky and block light nibble arrays. - */ - public static final int LIGHT_LENGTH = 16 * 16 * 16 / 2; // size * size * size / 2 (nibble bit count) - /** - * Length of the block data array. - */ - private final List palette = Lists.newArrayList(); - private final int[] blocks; - private final NibbleArray blockLight; - private NibbleArray skyLight; - - public ChunkSection1_9_1_2() { - this.blocks = new int[SIZE]; - this.blockLight = new NibbleArray(SIZE); - palette.add(0); // AIR - } - - /** - * Set a block in the chunks - * - * @param x Block X - * @param y Block Y - * @param z Block Z - * @param type The type of the block - * @param data The data value of the block - */ - public void setBlock(int x, int y, int z, int type, int data) { - setBlock(index(x, y, z), type, data); - } - - @Override - public void setFlatBlock(int x, int y, int z, int type) { - int index = palette.indexOf(type); - if (index == -1) { - index = palette.size(); - palette.add(type); - } - - blocks[index(x, y, z)] = index; - } - - public int getBlockId(int x, int y, int z) { - return getBlock(x, y, z) >> 4; - } - - public int getBlock(int x, int y, int z) { - int index = blocks[index(x, y, z)]; - return palette.get(index); - } - - /** - * Set a block in the chunks based on the index - * - * @param idx Index - * @param type The type of the block - * @param data The data value of the block - */ - public void setBlock(int idx, int type, int data) { - int hash = type << 4 | (data & 0xF); - int index = palette.indexOf(hash); - if (index == -1) { - index = palette.size(); - palette.add(hash); - } - - blocks[idx] = index; - } - - /** - * Set the block light array - * - * @param data The value to set the block light to - */ - public void setBlockLight(byte[] data) { - blockLight.setHandle(data); - } - - /** - * Set the sky light array - * - * @param data The value to set the sky light to - */ - public void setSkyLight(byte[] data) { - if (data.length != LIGHT_LENGTH) throw new IllegalArgumentException("Data length != " + LIGHT_LENGTH); - this.skyLight = new NibbleArray(data); - } - - private int index(int x, int y, int z) { - return y << 8 | z << 4 | x; - } - - /** - * Read blocks from input stream. - * This reads all the block related data: - *
    - *
  • Block length/palette type
  • - *
  • Palette
  • - *
  • Block hashes/palette reference
  • - *
- * - * @param input The buffer to read from. - * @throws Exception If it failed to read properly - */ - public void readBlocks(ByteBuf input) throws Exception { - palette.clear(); - - // Reaad bits per block - int bitsPerBlock = input.readUnsignedByte(); - long maxEntryValue = (1L << bitsPerBlock) - 1; - - if (bitsPerBlock == 0) { - bitsPerBlock = 13; - } - if (bitsPerBlock < 4) { - bitsPerBlock = 4; - } - if (bitsPerBlock > 8) { - bitsPerBlock = 13; - } - int paletteLength = Type.VAR_INT.read(input); - // Read palette - for (int i = 0; i < paletteLength; i++) { - if (bitsPerBlock != 13) { - palette.add(Type.VAR_INT.read(input)); - } else { - Type.VAR_INT.read(input); - } - } - - // Read blocks - // Long[] blockData = Type.LONG_ARRAY.read(input); - long[] blockData = new long[Type.VAR_INT.read(input)]; - for (int i = 0; i < blockData.length; i++) { - blockData[i] = input.readLong(); - } - if (blockData.length > 0) { - for (int i = 0; i < blocks.length; i++) { - int bitIndex = i * bitsPerBlock; - int startIndex = bitIndex / 64; - int endIndex = ((i + 1) * bitsPerBlock - 1) / 64; - int startBitSubIndex = bitIndex % 64; - int val; - if (startIndex == endIndex) { - val = (int) (blockData[startIndex] >>> startBitSubIndex & maxEntryValue); - } else { - int endBitSubIndex = 64 - startBitSubIndex; - val = (int) ((blockData[startIndex] >>> startBitSubIndex | blockData[endIndex] << endBitSubIndex) & maxEntryValue); - } - - if (bitsPerBlock == 13) { - int type = val >> 4; - int data = val & 0xF; - - setBlock(i, type, data); - } else { - blocks[i] = val; - } - } - } - } - - /** - * Read block light from buffer. - * - * @param input The buffer to read from - */ - public void readBlockLight(ByteBuf input) { - byte[] handle = new byte[LIGHT_LENGTH]; - input.readBytes(handle); - blockLight.setHandle(handle); - } - - /** - * Read sky light from buffer. - * Note: Only sent in overworld! - * - * @param input The buffer to read from - */ - public void readSkyLight(ByteBuf input) { - byte[] handle = new byte[LIGHT_LENGTH]; - input.readBytes(handle); - if (skyLight != null) { - skyLight.setHandle(handle); - return; - } - - this.skyLight = new NibbleArray(handle); - } - - /** - * Write the blocks to a buffer. - * - * @param output The buffer to write to. - * @throws Exception Throws if it failed to write. - */ - public void writeBlocks(ByteBuf output) throws Exception { - // Write bits per block - int bitsPerBlock = 4; - while (palette.size() > 1 << bitsPerBlock) { - bitsPerBlock += 1; - } - long maxEntryValue = (1L << bitsPerBlock) - 1; - output.writeByte(bitsPerBlock); - - // Write pallet (or not) - Type.VAR_INT.write(output, palette.size()); - for (int mappedId : palette) { - Type.VAR_INT.write(output, mappedId); - } - - int length = (int) Math.ceil(SIZE * bitsPerBlock / 64.0); - Type.VAR_INT.write(output, length); - long[] data = new long[length]; - for (int index = 0; index < blocks.length; index++) { - int value = blocks[index]; - int bitIndex = index * bitsPerBlock; - int startIndex = bitIndex / 64; - int endIndex = ((index + 1) * bitsPerBlock - 1) / 64; - int startBitSubIndex = bitIndex % 64; - data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex; - if (startIndex != endIndex) { - int endBitSubIndex = 64 - startBitSubIndex; - data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex; - } - } - for (long l : data) { - output.writeLong(l); - } - } - - @Override - public void writeBlocks1_13(ByteBuf output) throws Exception { - // Write bits per block - int bitsPerBlock = 4; - while (palette.size() > 1 << bitsPerBlock) { - bitsPerBlock++; - } - boolean directPalette = false; - if (bitsPerBlock >= 9) { - bitsPerBlock = 14; - directPalette = true; - } - long maxEntryValue = (1L << bitsPerBlock) - 1; - output.writeByte(bitsPerBlock); - - // Write pallet (or not) - if (!directPalette) { - Type.VAR_INT.write(output, palette.size()); - for (int mappedId : palette) { - Type.VAR_INT.write(output, mappedId); - } - } - - int length = (int) Math.ceil(SIZE * bitsPerBlock / 64.0); - Type.VAR_INT.write(output, length); - long[] data = new long[length]; - for (int index = 0; index < blocks.length; index++) { - int value = directPalette ? palette.get(blocks[index]) : blocks[index]; - int bitIndex = index * bitsPerBlock; - int startIndex = bitIndex / 64; - int endIndex = ((index + 1) * bitsPerBlock - 1) / 64; - int startBitSubIndex = bitIndex % 64; - data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex; - if (startIndex != endIndex) { - int endBitSubIndex = 64 - startBitSubIndex; - data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex; - } - } - for (long l : data) { - output.writeLong(l); - } - } - - /** - * Write the block light to a buffer - * - * @param output The buffer to write to - */ - public void writeBlockLight(ByteBuf output) { - output.writeBytes(blockLight.getHandle()); - } - - /** - * Write the sky light to a buffer - * - * @param output The buffer to write to - */ - public void writeSkyLight(ByteBuf output) { - output.writeBytes(skyLight.getHandle()); - } - - @Override - public List getPalette() { - return palette; - } - - /** - * Check if sky light is present - * - * @return True if skylight is present - */ - public boolean hasSkyLight() { - return skyLight != null; - } - - /** - * Get expected size of this chunks section. - * - * @return Amount of bytes sent by this section - * @throws Exception If it failed to calculate bits properly - */ - public int getExpectedSize() throws Exception { - int bitsPerBlock = palette.size() > 255 ? 16 : 8; - int bytes = 1; // bits per block - bytes += paletteBytes(); // palette - bytes += countBytes(bitsPerBlock == 16 ? SIZE * 2 : SIZE); // block data length - bytes += (palette.size() > 255 ? 2 : 1) * SIZE; // block data - bytes += LIGHT_LENGTH; // block light - bytes += hasSkyLight() ? LIGHT_LENGTH : 0; // sky light - return bytes; - } - - private int paletteBytes() throws Exception { - // Count bytes used by pallet - int bytes = countBytes(palette.size()); - for (int mappedId : palette) { - bytes += countBytes(mappedId); - } - return bytes; - } - - private int countBytes(int value) throws Exception { - // Count amount of bytes that would be sent if the value were sent as a VarInt - if ((value & (~0 << 7)) == 0) - return 1; - if ((value & (~0 << 14)) == 0) - return 2; - if ((value & (~0 << 21)) == 0) - return 3; - if ((value & (~0 << 28)) == 0) - return 4; - return 5; - } -} diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_3to1_9_1_2/types/Chunk1_9_1_2Type.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_3to1_9_1_2/types/Chunk1_9_1_2Type.java index 621c303ac..77d483144 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_3to1_9_1_2/types/Chunk1_9_1_2Type.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9_3to1_9_1_2/types/Chunk1_9_1_2Type.java @@ -9,10 +9,9 @@ import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; import us.myles.ViaVersion.api.type.PartialType; import us.myles.ViaVersion.api.type.Type; import us.myles.ViaVersion.api.type.types.minecraft.BaseChunkType; +import us.myles.ViaVersion.api.type.types.version.Types1_9; import us.myles.ViaVersion.protocols.base.ProtocolInfo; import us.myles.ViaVersion.protocols.protocol1_10to1_9_3.Protocol1_10To1_9_3_4; -import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.chunks.Chunk1_9_1_2; -import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.chunks.ChunkSection1_9_1_2; import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld; import java.util.ArrayList; @@ -37,7 +36,7 @@ public class Chunk1_9_1_2Type extends PartialType { int size = Type.VAR_INT.read(input); BitSet usedSections = new BitSet(16); - ChunkSection1_9_1_2[] sections = new ChunkSection1_9_1_2[16]; + ChunkSection[] sections = new ChunkSection[16]; // Calculate section count from bitmask for (int i = 0; i < 16; i++) { if ((primaryBitmask & (1 << i)) != 0) { @@ -48,9 +47,8 @@ public class Chunk1_9_1_2Type extends PartialType { // Read sections for (int i = 0; i < 16; i++) { if (!usedSections.get(i)) continue; // Section not set - ChunkSection1_9_1_2 section = new ChunkSection1_9_1_2(); + ChunkSection section = Types1_9.CHUNK_SECTION.read(input); sections[i] = section; - section.readBlocks(input); section.readBlockLight(input); if (world.getEnvironment() == Environment.NORMAL) { section.readSkyLight(input); @@ -67,7 +65,7 @@ public class Chunk1_9_1_2Type extends PartialType { input.readBytes(biomeData); } - return new Chunk1_9_1_2(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, new ArrayList()); + return new Chunk(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, new ArrayList()); } @Override @@ -82,7 +80,7 @@ public class Chunk1_9_1_2Type extends PartialType { for (int i = 0; i < 16; i++) { ChunkSection section = chunk.getSections()[i]; if (section == null) continue; // Section not set - section.writeBlocks(buf); + Types1_9.CHUNK_SECTION.write(buf, section); section.writeBlockLight(buf); if (!section.hasSkyLight()) continue; // No sky light, we're done here. diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/chunks/Chunk1_9to1_8.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/chunks/Chunk1_9to1_8.java index b80cecf30..dd775204d 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/chunks/Chunk1_9to1_8.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/chunks/Chunk1_9to1_8.java @@ -2,26 +2,20 @@ package us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.ToString; import us.myles.ViaVersion.api.minecraft.chunks.Chunk; +import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; import java.util.ArrayList; import java.util.List; -@RequiredArgsConstructor -@Getter -@ToString -public class Chunk1_9to1_8 implements Chunk { - private final int x; - private final int z; - private final boolean groundUp; - private final int primaryBitmask; - private final ChunkSection1_9to1_8[] sections; - private final byte[] biomeData; - private final List blockEntities; +public class Chunk1_9to1_8 extends Chunk { + @Getter private boolean unloadPacket = false; + public Chunk1_9to1_8(int x, int z, boolean groundUp, int bitmask, ChunkSection[] sections, byte[] biomeData, List blockEntities) { + super(x, z, groundUp, bitmask, sections, biomeData, blockEntities); + } + /** * Chunk unload. * @@ -29,8 +23,7 @@ public class Chunk1_9to1_8 implements Chunk { * @param z coord */ public Chunk1_9to1_8(int x, int z) { - this(x, z, true, 0, new ChunkSection1_9to1_8[16], null, - new ArrayList()); + this(x, z, true, 0, new ChunkSection[16], null, new ArrayList()); this.unloadPacket = true; } @@ -47,9 +40,4 @@ public class Chunk1_9to1_8 implements Chunk { public boolean isBiomeData() { return biomeData != null; } - - @Override - public int getBitmask() { - return primaryBitmask; - } } diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/chunks/ChunkSection1_9to1_8.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/chunks/ChunkSection1_9to1_8.java deleted file mode 100644 index e77518363..000000000 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/chunks/ChunkSection1_9to1_8.java +++ /dev/null @@ -1,263 +0,0 @@ -package us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks; - -import com.google.common.collect.Lists; -import io.netty.buffer.ByteBuf; -import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; -import us.myles.ViaVersion.api.minecraft.chunks.NibbleArray; -import us.myles.ViaVersion.api.type.Type; - -import java.util.List; - -public class ChunkSection1_9to1_8 implements ChunkSection { - /** - * Size (dimensions) of blocks in a chunks section. - */ - public static final int SIZE = 16 * 16 * 16; // width * depth * height - /** - * Length of the sky and block light nibble arrays. - */ - public static final int LIGHT_LENGTH = 16 * 16 * 16 / 2; // size * size * size / 2 (nibble bit count) - /** - * Length of the block data array. - */ - - private final List palette = Lists.newArrayList(); - private final int[] blocks; - private final NibbleArray blockLight; - private NibbleArray skyLight; - - public ChunkSection1_9to1_8() { - this.blocks = new int[SIZE]; - this.blockLight = new NibbleArray(SIZE); - palette.add(0); // AIR - } - - /** - * Set a block in the chunks - * - * @param x Block X - * @param y Block Y - * @param z Block Z - * @param type The type of the block - * @param data The data value of the block - */ - public void setBlock(int x, int y, int z, int type, int data) { - setBlock(index(x, y, z), type, data); - } - - @Override - public void setFlatBlock(int x, int y, int z, int type) { - int index = palette.indexOf(type); - if (index == -1) { - index = palette.size(); - palette.add(type); - } - - blocks[index(x, y, z)] = index; - } - - public int getBlockId(int x, int y, int z) { - return getBlock(x, y, z) >> 4; - } - - public int getBlock(int x, int y, int z) { - int index = blocks[index(x, y, z)]; - return palette.get(index); - } - - /** - * Set a block in the chunks based on the index - * - * @param idx Index - * @param type The type of the block - * @param data The data value of the block - */ - public void setBlock(int idx, int type, int data) { - int hash = type << 4 | (data & 0xF); - int index = palette.indexOf(hash); - if (index == -1) { - index = palette.size(); - palette.add(hash); - } - - blocks[idx] = index; - } - - /** - * Set the block light array - * - * @param data The value to set the block light to - */ - public void setBlockLight(byte[] data) { - blockLight.setHandle(data); - } - - /** - * Set the sky light array - * - * @param data The value to set the sky light to - */ - public void setSkyLight(byte[] data) { - if (data.length != LIGHT_LENGTH) throw new IllegalArgumentException("Data length != " + LIGHT_LENGTH); - this.skyLight = new NibbleArray(data); - } - - private int index(int x, int y, int z) { - return y << 8 | z << 4 | x; - } - - /** - * Write the blocks to a buffer. - * - * @param output The buffer to write to. - * @throws Exception Throws if it failed to write. - */ - public void writeBlocks(ByteBuf output) throws Exception { - // Write bits per block - int bitsPerBlock = 4; - while (palette.size() > 1 << bitsPerBlock) { - bitsPerBlock += 1; - } - long maxEntryValue = (1L << bitsPerBlock) - 1; - output.writeByte(bitsPerBlock); - - // Write pallet (or not) - Type.VAR_INT.write(output, palette.size()); - for (int mappedId : palette) { - Type.VAR_INT.write(output, mappedId); - } - - int length = (int) Math.ceil(SIZE * bitsPerBlock / 64.0); - Type.VAR_INT.write(output, length); - long[] data = new long[length]; - for (int index = 0; index < blocks.length; index++) { - int value = blocks[index]; - int bitIndex = index * bitsPerBlock; - int startIndex = bitIndex / 64; - int endIndex = ((index + 1) * bitsPerBlock - 1) / 64; - int startBitSubIndex = bitIndex % 64; - data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex; - if (startIndex != endIndex) { - int endBitSubIndex = 64 - startBitSubIndex; - data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex; - } - } - for (long l : data) { - output.writeLong(l); - } - } - - @Override - public void writeBlocks1_13(ByteBuf output) throws Exception { - // Write bits per block - int bitsPerBlock = 4; - while (palette.size() > 1 << bitsPerBlock) { - bitsPerBlock++; - } - boolean directPalette = false; - if (bitsPerBlock >= 9) { - bitsPerBlock = 14; - directPalette = true; - } - long maxEntryValue = (1L << bitsPerBlock) - 1; - output.writeByte(bitsPerBlock); - - // Write pallet (or not) - if (!directPalette) { - Type.VAR_INT.write(output, palette.size()); - for (int mappedId : palette) { - Type.VAR_INT.write(output, mappedId); - } - } - - int length = (int) Math.ceil(SIZE * bitsPerBlock / 64.0); - Type.VAR_INT.write(output, length); - long[] data = new long[length]; - for (int index = 0; index < blocks.length; index++) { - int value = directPalette ? palette.get(blocks[index]) : blocks[index]; - int bitIndex = index * bitsPerBlock; - int startIndex = bitIndex / 64; - int endIndex = ((index + 1) * bitsPerBlock - 1) / 64; - int startBitSubIndex = bitIndex % 64; - data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | ((long) value & maxEntryValue) << startBitSubIndex; - if (startIndex != endIndex) { - int endBitSubIndex = 64 - startBitSubIndex; - data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | ((long) value & maxEntryValue) >> endBitSubIndex; - } - } - for (long l : data) { - output.writeLong(l); - } - } - - /** - * Write the block light to a buffer - * - * @param output The buffer to write to - */ - public void writeBlockLight(ByteBuf output) { - output.writeBytes(blockLight.getHandle()); - } - - /** - * Write the sky light to a buffer - * - * @param output The buffer to write to - */ - public void writeSkyLight(ByteBuf output) { - output.writeBytes(skyLight.getHandle()); - } - - @Override - public List getPalette() { - return palette; - } - - /** - * Check if sky light is present - * - * @return True if skylight is present - */ - public boolean hasSkyLight() { - return skyLight != null; - } - - /** - * Get expected size of this chunks section. - * - * @return Amount of bytes sent by this section - * @throws Exception If it failed to calculate bits properly - */ - public int getExpectedSize() throws Exception { - int bitsPerBlock = palette.size() > 255 ? 16 : 8; - int bytes = 1; // bits per block - bytes += paletteBytes(); // palette - bytes += countBytes(bitsPerBlock == 16 ? SIZE * 2 : SIZE); // block data length - bytes += (palette.size() > 255 ? 2 : 1) * SIZE; // block data - bytes += LIGHT_LENGTH; // block light - bytes += hasSkyLight() ? LIGHT_LENGTH : 0; // sky light - return bytes; - } - - private int paletteBytes() throws Exception { - // Count bytes used by pallet - int bytes = countBytes(palette.size()); - for (int mappedId : palette) { - bytes += countBytes(mappedId); - } - return bytes; - } - - private int countBytes(int value) throws Exception { - // Count amount of bytes that would be sent if the value were sent as a VarInt - if ((value & (~0 << 7)) == 0) - return 1; - if ((value & (~0 << 14)) == 0) - return 2; - if ((value & (~0 << 21)) == 0) - return 3; - if ((value & (~0 << 28)) == 0) - return 4; - return 5; - } -} diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/packets/WorldPackets.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/packets/WorldPackets.java index 8a60e7b57..f6605c692 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/packets/WorldPackets.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/packets/WorldPackets.java @@ -24,7 +24,7 @@ import us.myles.ViaVersion.protocols.protocol1_9to1_8.sounds.SoundEffect; import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks; import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.EntityTracker; import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.PlaceBlockTracker; -import us.myles.ViaVersion.protocols.protocol1_9to1_8.types.ChunkType; +import us.myles.ViaVersion.protocols.protocol1_9to1_8.types.Chunk1_9to1_8Type; import java.io.IOException; import java.util.List; @@ -121,7 +121,7 @@ public class WorldPackets { @Override public void handle(PacketWrapper wrapper) throws Exception { ClientChunks clientChunks = wrapper.user().get(ClientChunks.class); - Chunk1_9to1_8 chunk = (Chunk1_9to1_8) wrapper.passthrough(new ChunkType(clientChunks)); + Chunk1_9to1_8 chunk = (Chunk1_9to1_8) wrapper.passthrough(new Chunk1_9to1_8Type(clientChunks)); if (chunk.isUnloadPacket()) { wrapper.setId(0x1D); diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/types/ChunkType.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/types/Chunk1_9to1_8Type.java similarity index 75% rename from common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/types/ChunkType.java rename to common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/types/Chunk1_9to1_8Type.java index eda3efd5b..40115b9a4 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/types/ChunkType.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/types/Chunk1_9to1_8Type.java @@ -4,23 +4,22 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import io.netty.buffer.ByteBuf; import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.minecraft.chunks.Chunk; +import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; import us.myles.ViaVersion.api.type.PartialType; import us.myles.ViaVersion.api.type.Type; import us.myles.ViaVersion.api.type.types.minecraft.BaseChunkType; +import us.myles.ViaVersion.api.type.types.version.Types1_8; +import us.myles.ViaVersion.api.type.types.version.Types1_9; import us.myles.ViaVersion.protocols.base.ProtocolInfo; import us.myles.ViaVersion.protocols.protocol1_10to1_9_3.Protocol1_10To1_9_3_4; import us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks.Chunk1_9to1_8; -import us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks.ChunkSection1_9to1_8; import us.myles.ViaVersion.protocols.protocol1_9to1_8.storage.ClientChunks; -import java.nio.ByteBuffer; -import java.nio.ByteOrder; -import java.nio.ShortBuffer; import java.util.ArrayList; import java.util.BitSet; import java.util.logging.Level; -public class ChunkType extends PartialType { +public class Chunk1_9to1_8Type extends PartialType { /** * Amount of sections in a chunks. */ @@ -34,7 +33,7 @@ public class ChunkType extends PartialType { */ private static final int BIOME_DATA_LENGTH = 256; - public ChunkType(ClientChunks chunks) { + public Chunk1_9to1_8Type(ClientChunks chunks) { super(chunks, Chunk.class); } @@ -61,7 +60,7 @@ public class ChunkType extends PartialType { // Data to be read BitSet usedSections = new BitSet(16); - ChunkSection1_9to1_8[] sections = new ChunkSection1_9to1_8[16]; + ChunkSection[] sections = new ChunkSection[16]; byte[] biomeData = null; // Calculate section count from bitmask @@ -87,41 +86,27 @@ public class ChunkType extends PartialType { // Read blocks for (int i = 0; i < SECTION_COUNT; i++) { if (!usedSections.get(i)) continue; // Section not set - ChunkSection1_9to1_8 section = new ChunkSection1_9to1_8(); + ChunkSection section = Types1_8.CHUNK_SECTION.read(input); sections[i] = section; - // Read block data and convert to short buffer - byte[] blockData = new byte[ChunkSection1_9to1_8.SIZE * 2]; - input.readBytes(blockData); - ShortBuffer blockBuf = ByteBuffer.wrap(blockData).order(ByteOrder.LITTLE_ENDIAN).asShortBuffer(); - - for (int j = 0; j < ChunkSection1_9to1_8.SIZE; j++) { - int mask = blockBuf.get(); - int type = mask >> 4; - int data = mask & 0xF; - if (replacePistons && type == 36) - type = replacementId; - section.setBlock(j, type, data); + if (replacePistons && section.getPalette().contains(36)) { + section.getPalette().set(section.getPalette().indexOf(36), replacementId); } } // Read block light for (int i = 0; i < SECTION_COUNT; i++) { if (!usedSections.get(i)) continue; // Section not set, has no light - byte[] blockLightArray = new byte[ChunkSection1_9to1_8.LIGHT_LENGTH]; - input.readBytes(blockLightArray); - sections[i].setBlockLight(blockLightArray); + sections[i].readBlockLight(input); } // Read sky light int bytesLeft = dataLength - (input.readerIndex() - startIndex); - if (bytesLeft >= ChunkSection1_9to1_8.LIGHT_LENGTH) { + if (bytesLeft >= ChunkSection.LIGHT_LENGTH) { for (int i = 0; i < SECTION_COUNT; i++) { if (!usedSections.get(i)) continue; // Section not set, has no light - byte[] skyLightArray = new byte[ChunkSection1_9to1_8.LIGHT_LENGTH]; - input.readBytes(skyLightArray); - sections[i].setSkyLight(skyLightArray); - bytesLeft -= ChunkSection1_9to1_8.LIGHT_LENGTH; + sections[i].readSkyLight(input); + bytesLeft -= ChunkSection.LIGHT_LENGTH; } } @@ -151,13 +136,13 @@ public class ChunkType extends PartialType { output.writeInt(chunk.getZ()); if (chunk.isUnloadPacket()) return; output.writeByte(chunk.isGroundUp() ? 0x01 : 0x00); - Type.VAR_INT.write(output, chunk.getPrimaryBitmask()); + Type.VAR_INT.write(output, chunk.getBitmask()); ByteBuf buf = output.alloc().buffer(); for (int i = 0; i < SECTION_COUNT; i++) { - ChunkSection1_9to1_8 section = chunk.getSections()[i]; + ChunkSection section = chunk.getSections()[i]; if (section == null) continue; // Section not set - section.writeBlocks(buf); + Types1_9.CHUNK_SECTION.write(buf, section); section.writeBlockLight(buf); if (!section.hasSkyLight()) continue; // No sky light, we're done here.