From 54ad8606dcb206dd3de33b43cc2fcc43a0587ae3 Mon Sep 17 00:00:00 2001 From: creeper123123321 Date: Wed, 18 Jul 2018 13:23:57 -0300 Subject: [PATCH] Chunk1_13 - not tested --- .../api/minecraft/chunks/ChunkSection.java | 48 ++- .../chunks/ChunkSection1_9_3_4.java | 43 +++ .../chunks/ChunkSection1_9_1_2.java | 43 +++ .../chunks/ChunkSection1_9to1_8.java | 43 +++ .../chunks/Chunk1_13.java | 25 ++ .../chunks/ChunkSection1_13.java | 306 ++++++++++++++++++ .../types/Chunk1_13Type.java | 13 +- 7 files changed, 513 insertions(+), 8 deletions(-) create mode 100644 common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/chunks/Chunk1_13.java create mode 100644 common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/chunks/ChunkSection1_13.java 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 5601c59f1..6e3e7cd60 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 @@ -5,16 +5,62 @@ import io.netty.buffer.ByteBuf; import java.util.List; public interface 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 + */ int getBlock(int x, int y, int z); + /** + * Set a block in the chunks + * + * @param x Block X + * @param y Block Y + * @param z Block Z + * @param type The block id + * @param data The data value of the block + */ void setBlock(int x, int y, int z, int type, int data); - void setFlatBlock(int x, int y, int z, int type); + /** + * Set a block state in the chunk + * + * @param x Block X + * @param y Block Y + * @param z Block Z + * @param blockState The block state id + */ + void setFlatBlock(int x, int y, int z, int blockState); + /** + * Gets a block id (without data) + * /!\ YOU SHOULD NOT USE THIS ON 1.13 + * @param x Block X + * @param y Block Y + * @param z Block Z + * @return Block id (without data) + */ int getBlockId(int x, int y, int z); + /** + * Write the blocks in < 1.13 format to a buffer. + * + * @param output The buffer to write to. + * @throws Exception Throws if it failed to write. + */ void writeBlocks(ByteBuf output) throws Exception; + /** + * Write the blocks in 1.13 format to a buffer. + * + * @param output The buffer to write to. + * @throws Exception Throws if it failed to write. + */ + void writeBlocks1_13(ByteBuf output) throws Exception; + void writeBlockLight(ByteBuf output) throws Exception; boolean hasSkyLight(); 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 index 0b3269d0a..ca4b45d6d 100644 --- 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 @@ -249,6 +249,49 @@ public class ChunkSection1_9_3_4 implements ChunkSection { } } + @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) { + Type.LONG.write(output, l); + } + } + /** * Write the block light to a buffer * 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 index 0c5cba766..45131c509 100644 --- 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 @@ -241,6 +241,49 @@ public class ChunkSection1_9_1_2 implements ChunkSection { } } + @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) { + Type.LONG.write(output, l); + } + } + /** * Write the block light to a buffer * 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 index 169da097e..9033929ab 100644 --- 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 @@ -148,6 +148,49 @@ public class ChunkSection1_9to1_8 implements ChunkSection { } } + @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) { + Type.LONG.write(output, l); + } + } + /** * Write the block light to a buffer * diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/chunks/Chunk1_13.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/chunks/Chunk1_13.java new file mode 100644 index 000000000..3f2b16792 --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/chunks/Chunk1_13.java @@ -0,0 +1,25 @@ +package us.myles.ViaVersion.protocols.protocolsnapshotto1_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/protocolsnapshotto1_12_2/chunks/ChunkSection1_13.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/chunks/ChunkSection1_13.java new file mode 100644 index 000000000..d74e750c8 --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/chunks/ChunkSection1_13.java @@ -0,0 +1,306 @@ +package us.myles.ViaVersion.protocols.protocolsnapshotto1_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 = 13; + } + 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); + 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) { + Type.LONG.write(output, 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) { + Type.LONG.write(output, 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/protocolsnapshotto1_12_2/types/Chunk1_13Type.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/types/Chunk1_13Type.java index b7960320d..a07b475aa 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/types/Chunk1_13Type.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocolsnapshotto1_12_2/types/Chunk1_13Type.java @@ -10,16 +10,15 @@ 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.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld; +import us.myles.ViaVersion.protocols.protocolsnapshotto1_12_2.chunks.Chunk1_13; +import us.myles.ViaVersion.protocols.protocolsnapshotto1_12_2.chunks.ChunkSection1_13; import java.util.ArrayList; import java.util.Arrays; import java.util.BitSet; import java.util.List; -// todo 1.13-pre2 direct pallete changes public class Chunk1_13Type extends PartialType { public Chunk1_13Type(ClientWorld param) { super(param, Chunk.class); @@ -35,7 +34,7 @@ public class Chunk1_13Type extends PartialType { Type.VAR_INT.read(input); BitSet usedSections = new BitSet(16); - ChunkSection1_9_3_4[] sections = new ChunkSection1_9_3_4[16]; + ChunkSection1_13[] sections = new ChunkSection1_13[16]; // Calculate section count from bitmask for (int i = 0; i < 16; i++) { if ((primaryBitmask & (1 << i)) != 0) { @@ -46,7 +45,7 @@ public class Chunk1_13Type 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(); + ChunkSection1_13 section = new ChunkSection1_13(); sections[i] = section; section.readBlocks(input); section.readBlockLight(input); @@ -72,7 +71,7 @@ public class Chunk1_13Type extends PartialType { System.out.println("Found " + array.length + " more bytes than expected while reading the chunk: " + chunkX + "/" + chunkZ); } - return new Chunk1_9_3_4(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, nbtData); + return new Chunk1_13(chunkX, chunkZ, groundUp, primaryBitmask, sections, biomeData, nbtData); } @Override @@ -87,7 +86,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.writeBlocks(buf); + section.writeBlocks1_13(buf); section.writeBlockLight(buf); if (!section.hasSkyLight()) continue; // No sky light, we're done here.