diff --git a/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/BaseChunk.java b/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/BaseChunk.java new file mode 100644 index 000000000..82dd09429 --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/BaseChunk.java @@ -0,0 +1,24 @@ +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; + +@AllArgsConstructor +@Data +public class BaseChunk implements Chunk { + protected int x; + protected int z; + protected boolean groundUp; + protected int bitmask; + protected ChunkSection[] sections; + protected byte[] biomeData; + protected List blockEntities; + + @Override + public boolean isBiomeData() { + return biomeData != null; + } +} 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..f5b078748 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 @@ -9,15 +9,15 @@ public interface Chunk { int getZ(); - ChunkSection[] getSections(); - - boolean isGroundUp(); - boolean isBiomeData(); - byte[] getBiomeData(); - int getBitmask(); + ChunkSection[] getSections(); + + byte[] getBiomeData(); + List getBlockEntities(); + + boolean isGroundUp(); } diff --git a/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/Chunk1_8.java b/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/Chunk1_8.java new file mode 100644 index 000000000..4bfe7f3ed --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/api/minecraft/chunks/Chunk1_8.java @@ -0,0 +1,41 @@ +package us.myles.ViaVersion.api.minecraft.chunks; + +import com.github.steveice10.opennbt.tag.builtin.CompoundTag; +import lombok.Getter; + +import java.util.ArrayList; +import java.util.List; + +public class Chunk1_8 extends BaseChunk { + @Getter + private boolean unloadPacket = false; + + public Chunk1_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. + * + * @param x coord + * @param z coord + */ + public Chunk1_8(int x, int z) { + this(x, z, true, 0, new ChunkSection[16], null, new ArrayList()); + this.unloadPacket = true; + } + + /** + * Does this chunks have biome data + * + * @return True if the chunks has biome data + */ + public boolean hasBiomeData() { + return biomeData != null && groundUp; + } + + @Override + 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..9305a5994 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,73 +1,221 @@ package us.myles.ViaVersion.api.minecraft.chunks; import io.netty.buffer.ByteBuf; +import lombok.Getter; +import lombok.Setter; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; -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) + private List palette = new ArrayList<>(); + private Map inversePalette = new HashMap<>(); + private final int[] blocks; + private NibbleArray blockLight; + private NibbleArray skyLight; + @Getter + @Setter + private int nonAirBlocksCount; + + public ChunkSection() { + this.blocks = new int[SIZE]; + this.blockLight = new NibbleArray(SIZE); + palette.add(0); + inversePalette.put(0, 0); + } /** * Set a block in the chunks + * This method will not update non-air blocks count * * @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]; + } + + public int getPaletteSize() { + return palette.size(); + } + + public int getPaletteEntry(int index) { + if (index < 0 || index >= palette.size()) throw new IndexOutOfBoundsException(); + return palette.get(index); + } + + public void setPaletteEntry(int index, int id) { + if (index < 0 || index >= palette.size()) throw new IndexOutOfBoundsException(); + palette.set(index, id); + inversePalette.put(id, index); + } + + public void replacePaletteEntry(int oldId, int newId) { + Integer index = inversePalette.remove(oldId); + if (index == null) return; + inversePalette.put(newId, index); + for (int i = 0; i < palette.size(); i++) { + if (palette.get(i) == oldId) palette.set(i, newId); + } + } + + public void addPaletteEntry(int id) { + inversePalette.put(id, palette.size()); + palette.add(id); + } + + public void clearPalette() { + palette.clear(); + inversePalette.clear(); + } /** * Set a block state in the chunk + * This method will not update non-air blocks count * - * @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) { + Integer index = inversePalette.get(id); + if (index == null) { + index = palette.size(); + palette.add(id); + inversePalette.put(id, index); + } + + 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(); + /** + * Check if sky light is present + * + * @return True if skylight is present + */ + public boolean hasSkyLight() { + return skyLight != null; + } - void writeSkyLight(ByteBuf output) throws Exception; - - 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..e6e265475 --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_13.java @@ -0,0 +1,109 @@ +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; + +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(); + + // 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 + chunkSection.clearPalette(); + for (int i = 0; i < paletteLength; i++) { + chunkSection.addPaletteEntry(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 { + int bitsPerBlock = 4; + while (chunkSection.getPaletteSize() > 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, chunkSection.getPaletteSize()); + for (int i = 0; i < chunkSection.getPaletteSize(); i++) { + Type.VAR_INT.write(buffer, chunkSection.getPaletteEntry(i)); + } + } + + 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..2cc3f478b --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_8.java @@ -0,0 +1,40 @@ +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.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.ShortBuffer; + +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(); + chunkSection.clearPalette(); + + 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 UnsupportedOperationException(); + } +} 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..8a596e24a --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/api/type/types/version/ChunkSectionType1_9.java @@ -0,0 +1,106 @@ +package us.myles.ViaVersion.api.type.types.version; + +import com.google.common.collect.BiMap; +import io.netty.buffer.ByteBuf; +import us.myles.ViaVersion.api.minecraft.chunks.ChunkSection; +import us.myles.ViaVersion.api.type.Type; + +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(); + + // 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 + chunkSection.clearPalette(); + for (int i = 0; i < paletteLength; i++) { + if (bitsPerBlock != 13) { + chunkSection.addPaletteEntry(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 { + int bitsPerBlock = 4; + while (chunkSection.getPaletteSize() > 1 << bitsPerBlock) { + bitsPerBlock += 1; + } + long maxEntryValue = (1L << bitsPerBlock) - 1; + buffer.writeByte(bitsPerBlock); + + // Write pallet + Type.VAR_INT.write(buffer, chunkSection.getPaletteSize()); + for (int i = 0; i < chunkSection.getPaletteSize(); i++) { + Type.VAR_INT.write(buffer, chunkSection.getPaletteEntry(i)); + } + + 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_13_1to1_13/packets/WorldPackets.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13_1to1_13/packets/WorldPackets.java index 4e91dfee5..f643d423f 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13_1to1_13/packets/WorldPackets.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_13_1to1_13/packets/WorldPackets.java @@ -27,16 +27,11 @@ public class WorldPackets { Chunk chunk = wrapper.passthrough(new Chunk1_13Type(clientWorld)); for (ChunkSection section : chunk.getSections()) { - if (section != null) { - for (int i = 0; i < section.getPalette().size(); i++) { - section.getPalette().set( - i, - Protocol1_13_1To1_13.getNewBlockStateId(section.getPalette().get(i)) - ); - } + if (section == null) continue; + for (int i = 0; i < section.getPaletteSize(); i++) { + section.setPaletteEntry(i, Protocol1_13_1To1_13.getNewBlockStateId(section.getPaletteEntry(i))); } } - } }); } 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..813732bc6 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 @@ -2,6 +2,7 @@ package us.myles.ViaVersion.protocols.protocol1_13to1_12_2.packets; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.google.common.base.Optional; +import com.google.common.collect.BiMap; import us.myles.ViaVersion.api.PacketWrapper; import us.myles.ViaVersion.api.Via; import us.myles.ViaVersion.api.data.UserConnection; @@ -241,20 +242,20 @@ public class WorldPackets { boolean willStoreAnyBlock = false; - for (int p = 0; p < section.getPalette().size(); p++) { - int old = section.getPalette().get(p); + for (int p = 0; p < section.getPaletteSize(); p++) { + int old = section.getPaletteEntry(p); int newId = toNewId(old); if (storage.isWelcome(newId)) { willStoreAnyBlock = true; } - section.getPalette().set(p, newId); + section.setPaletteEntry(p, newId); } if (willStoreAnyBlock) { 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..3d4e40154 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 @@ -4,13 +4,13 @@ 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.Environment; +import us.myles.ViaVersion.api.minecraft.chunks.BaseChunk; 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.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 +33,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 +44,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 +70,7 @@ public class Chunk1_13Type extends PartialType { } } - return new Chunk1_13(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, nbtData); + return new BaseChunk(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, nbtData); } @Override @@ -86,7 +85,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..5f7188ca4 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 @@ -4,13 +4,13 @@ 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.Environment; +import us.myles.ViaVersion.api.minecraft.chunks.BaseChunk; 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.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 +34,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 +45,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 +68,7 @@ public class Chunk1_9_3_4Type extends PartialType { } } - return new Chunk1_9_3_4(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, nbtData); + return new BaseChunk(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, nbtData); } @Override @@ -84,7 +83,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..64a0bc949 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 @@ -4,15 +4,15 @@ 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.Environment; +import us.myles.ViaVersion.api.minecraft.chunks.BaseChunk; 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_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 +37,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,17 +48,14 @@ 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); } if (replacePistons) { - if (section.getPalette().contains(36)) { - section.getPalette().set(section.getPalette().indexOf(36), replacementId); - } + section.replacePaletteEntry(36, replacementId); } } @@ -67,7 +64,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 BaseChunk(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, new ArrayList()); } @Override @@ -82,7 +79,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 deleted file mode 100644 index b80cecf30..000000000 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_9to1_8/chunks/Chunk1_9to1_8.java +++ /dev/null @@ -1,55 +0,0 @@ -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 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; - private boolean unloadPacket = false; - - /** - * Chunk unload. - * - * @param x coord - * @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.unloadPacket = true; - } - - /** - * Does this chunks have biome data - * - * @return True if the chunks has biome data - */ - public boolean hasBiomeData() { - return biomeData != null && groundUp; - } - - @Override - 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..0b0540559 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 @@ -16,7 +16,7 @@ import us.myles.ViaVersion.api.type.Type; import us.myles.ViaVersion.packets.State; import us.myles.ViaVersion.protocols.protocol1_9to1_8.ItemRewriter; import us.myles.ViaVersion.protocols.protocol1_9to1_8.Protocol1_9TO1_8; -import us.myles.ViaVersion.protocols.protocol1_9to1_8.chunks.Chunk1_9to1_8; +import us.myles.ViaVersion.api.minecraft.chunks.Chunk1_8; import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.BulkChunkTranslatorProvider; import us.myles.ViaVersion.protocols.protocol1_9to1_8.providers.CommandBlockProvider; import us.myles.ViaVersion.protocols.protocol1_9to1_8.sounds.Effect; @@ -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,16 +121,20 @@ 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_8Type type = new Chunk1_9to1_8Type(clientChunks); + Chunk1_8 chunk = (Chunk1_8) wrapper.read(type); if (chunk.isUnloadPacket()) { wrapper.setId(0x1D); + wrapper.write(Type.INT, chunk.getX()); + wrapper.write(Type.INT, chunk.getZ()); // Remove commandBlocks on chunk unload CommandBlockProvider provider = Via.getManager().getProviders().get(CommandBlockProvider.class); provider.unloadChunk(wrapper.user(), chunk.getX(), chunk.getZ()); + } else { + wrapper.write(type, chunk); + // eat any other data (Usually happens with unload packets) } - - // eat any other data (Usually happens with unload packets) wrapper.read(Type.REMAINING_BYTES); } }); 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 69% 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..4f2d47b18 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.api.minecraft.chunks.Chunk1_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 @@ -78,7 +77,7 @@ public class ChunkType extends PartialType { if (sectionCount == 0 && groundUp && !isBulkPacket && param.getLoadedChunks().contains(chunkHash)) { // This is a chunks unload packet param.getLoadedChunks().remove(chunkHash); - return new Chunk1_9to1_8(chunkX, chunkZ); + return new Chunk1_8(chunkX, chunkZ); } int startIndex = input.readerIndex(); @@ -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.replacePaletteEntry(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; } } @@ -138,26 +123,26 @@ public class ChunkType extends PartialType { } // Return chunks - return new Chunk1_9to1_8(chunkX, chunkZ, groundUp, bitmask, sections, biomeData, new ArrayList()); + return new Chunk1_8(chunkX, chunkZ, groundUp, bitmask, sections, biomeData, new ArrayList()); } @Override public void write(ByteBuf output, ClientChunks param, Chunk input) throws Exception { - if (!(input instanceof Chunk1_9to1_8)) throw new Exception("Incompatible chunk, " + input.getClass()); + if (!(input instanceof Chunk1_8)) throw new Exception("Incompatible chunk, " + input.getClass()); - Chunk1_9to1_8 chunk = (Chunk1_9to1_8) input; + Chunk1_8 chunk = (Chunk1_8) input; // Write primary info output.writeInt(chunk.getX()); 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.