From 005c91eb4db8b5b327f73c578b37eacf7bbc02cf Mon Sep 17 00:00:00 2001 From: creeper123123321 <7974274+creeper123123321@users.noreply.github.com> Date: Sat, 19 Oct 2019 15:31:50 -0300 Subject: [PATCH] deduplicate minecraft compact array code/decode --- .../types/version/ChunkSectionType1_13.java | 44 +++--------------- .../types/version/ChunkSectionType1_9.java | 42 +++-------------- .../packets/WorldPackets.java | 25 ++--------- .../myles/ViaVersion/util/BiIntConsumer.java | 6 +++ .../ViaVersion/util/CompactArrayUtil.java | 45 +++++++++++++++++++ 5 files changed, 68 insertions(+), 94 deletions(-) create mode 100644 common/src/main/java/us/myles/ViaVersion/util/BiIntConsumer.java create mode 100644 common/src/main/java/us/myles/ViaVersion/util/CompactArrayUtil.java 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 index bba7a593b..171915be3 100644 --- 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 @@ -3,6 +3,7 @@ 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 us.myles.ViaVersion.util.CompactArrayUtil; public class ChunkSectionType1_13 extends Type { private static final int GLOBAL_PALETTE = 14; @@ -23,8 +24,6 @@ public class ChunkSectionType1_13 extends Type { bitsPerBlock = GLOBAL_PALETTE; } - long maxEntryValue = (1L << bitsPerBlock) - 1; - int paletteLength = bitsPerBlock == GLOBAL_PALETTE ? 0 : Type.VAR_INT.read(buffer); // Read palette chunkSection.clearPalette(); @@ -43,25 +42,9 @@ public class ChunkSectionType1_13 extends Type { 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 == GLOBAL_PALETTE) { - chunkSection.setFlatBlock(i, val); - } else { - chunkSection.setPaletteIndex(i, val); - } - } + CompactArrayUtil.iterateCompactArray(bitsPerBlock, ChunkSection.SIZE, blockData, + bitsPerBlock == GLOBAL_PALETTE ? (i, val) -> chunkSection.setBlock(i, val >> 4, val & 0xF) + : chunkSection::setPaletteIndex); } return chunkSection; @@ -78,7 +61,6 @@ public class ChunkSectionType1_13 extends Type { bitsPerBlock = GLOBAL_PALETTE; } - long maxEntryValue = (1L << bitsPerBlock) - 1; buffer.writeByte(bitsPerBlock); // Write pallet (or not) @@ -89,21 +71,9 @@ public class ChunkSectionType1_13 extends Type { } } - 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 == GLOBAL_PALETTE ? 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; - } - } + long[] data = CompactArrayUtil.createCompactArray(bitsPerBlock, ChunkSection.SIZE, + bitsPerBlock == GLOBAL_PALETTE ? chunkSection::getFlatBlock : chunkSection::getPaletteIndex); + Type.VAR_INT.write(buffer, data.length); for (long l : data) { buffer.writeLong(l); } 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 index 8d11a517b..b91f69747 100644 --- 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 @@ -3,6 +3,7 @@ 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 us.myles.ViaVersion.util.CompactArrayUtil; public class ChunkSectionType1_9 extends Type { private static final int GLOBAL_PALETTE = 13; @@ -18,7 +19,6 @@ public class ChunkSectionType1_9 extends Type { // Reaad bits per block int bitsPerBlock = buffer.readUnsignedByte(); int originalBitsPerBlock = bitsPerBlock; - long maxEntryValue = (1L << bitsPerBlock) - 1; if (bitsPerBlock == 0) { bitsPerBlock = GLOBAL_PALETTE; @@ -51,25 +51,9 @@ public class ChunkSectionType1_9 extends Type { 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 == GLOBAL_PALETTE) { - chunkSection.setBlock(i, val >> 4, val & 0xF); - } else { - chunkSection.setPaletteIndex(i, val); - } - } + CompactArrayUtil.iterateCompactArray(bitsPerBlock, ChunkSection.SIZE, blockData, + bitsPerBlock == GLOBAL_PALETTE ? (i, val) -> chunkSection.setBlock(i, val >> 4, val & 0xF) + : chunkSection::setPaletteIndex); } return chunkSection; @@ -99,21 +83,9 @@ public class ChunkSectionType1_9 extends Type { Type.VAR_INT.write(buffer, 0); } - 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 == GLOBAL_PALETTE ? 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; - } - } + long[] data = CompactArrayUtil.createCompactArray(bitsPerBlock, ChunkSection.SIZE, + bitsPerBlock == GLOBAL_PALETTE ? chunkSection::getFlatBlock : chunkSection::getPaletteIndex); + Type.VAR_INT.write(buffer, data.length); for (long l : data) { buffer.writeLong(l); } diff --git a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_14to1_13_2/packets/WorldPackets.java b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_14to1_13_2/packets/WorldPackets.java index f07009be9..4de02892f 100644 --- a/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_14to1_13_2/packets/WorldPackets.java +++ b/common/src/main/java/us/myles/ViaVersion/protocols/protocol1_14to1_13_2/packets/WorldPackets.java @@ -4,7 +4,6 @@ import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.LongArrayTag; import us.myles.ViaVersion.api.PacketWrapper; import us.myles.ViaVersion.api.Via; -import us.myles.ViaVersion.api.data.UserConnection; import us.myles.ViaVersion.api.entities.Entity1_14Types; import us.myles.ViaVersion.api.minecraft.BlockChangeRecord; import us.myles.ViaVersion.api.minecraft.BlockFace; @@ -18,12 +17,13 @@ import us.myles.ViaVersion.api.remapper.ValueCreator; import us.myles.ViaVersion.api.type.Type; import us.myles.ViaVersion.packets.State; import us.myles.ViaVersion.protocols.protocol1_13to1_12_2.types.Chunk1_13Type; -import us.myles.ViaVersion.protocols.protocol1_14to1_13_2.metadata.MetadataRewriter1_14To1_13_2; import us.myles.ViaVersion.protocols.protocol1_14to1_13_2.Protocol1_14To1_13_2; import us.myles.ViaVersion.protocols.protocol1_14to1_13_2.data.MappingData; +import us.myles.ViaVersion.protocols.protocol1_14to1_13_2.metadata.MetadataRewriter1_14To1_13_2; import us.myles.ViaVersion.protocols.protocol1_14to1_13_2.storage.EntityTracker1_14; import us.myles.ViaVersion.protocols.protocol1_14to1_13_2.types.Chunk1_14Type; import us.myles.ViaVersion.protocols.protocol1_9_3to1_9_1_2.storage.ClientWorld; +import us.myles.ViaVersion.util.CompactArrayUtil; import java.util.Arrays; @@ -435,26 +435,7 @@ public class WorldPackets { } private static long[] encodeHeightMap(int[] heightMap) { - final int bitsPerBlock = 9; - long maxEntryValue = (1L << bitsPerBlock) - 1; - - int length = (int) Math.ceil(heightMap.length * bitsPerBlock / 64.0); - long[] data = new long[length]; - - for (int index = 0; index < heightMap.length; index++) { - int value = heightMap[index]; - int bitIndex = index * 9; - 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; - } - } - - return data; + return CompactArrayUtil.createCompactArray(9, heightMap.length, i -> heightMap[i]); } private static void setNonFullLight(Chunk chunk, ChunkSection section, int ySection, int x, int y, int z) { diff --git a/common/src/main/java/us/myles/ViaVersion/util/BiIntConsumer.java b/common/src/main/java/us/myles/ViaVersion/util/BiIntConsumer.java new file mode 100644 index 000000000..6c2a43d0e --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/util/BiIntConsumer.java @@ -0,0 +1,6 @@ +package us.myles.ViaVersion.util; + +@FunctionalInterface +public interface BiIntConsumer { + void consume(int i1, int i2); +} diff --git a/common/src/main/java/us/myles/ViaVersion/util/CompactArrayUtil.java b/common/src/main/java/us/myles/ViaVersion/util/CompactArrayUtil.java new file mode 100644 index 000000000..92c0d40b1 --- /dev/null +++ b/common/src/main/java/us/myles/ViaVersion/util/CompactArrayUtil.java @@ -0,0 +1,45 @@ +package us.myles.ViaVersion.util; + +import java.util.function.IntToLongFunction; + +public class CompactArrayUtil { + private CompactArrayUtil() { + throw new AssertionError(); + } + + public static long[] createCompactArray(int bitsPerEntry, int entries, IntToLongFunction valueGetter) { + long maxEntryValue = (1L << bitsPerEntry) - 1; + long[] data = new long[(int) Math.ceil(entries * bitsPerEntry / 64.0)]; + for (int index = 0; index < entries; index++) { + long value = valueGetter.applyAsLong(index); + int bitIndex = index * bitsPerEntry; + int startIndex = bitIndex / 64; + int endIndex = ((index + 1) * bitsPerEntry - 1) / 64; + int startBitSubIndex = bitIndex % 64; + data[startIndex] = data[startIndex] & ~(maxEntryValue << startBitSubIndex) | (value & maxEntryValue) << startBitSubIndex; + if (startIndex != endIndex) { + int endBitSubIndex = 64 - startBitSubIndex; + data[endIndex] = data[endIndex] >>> endBitSubIndex << endBitSubIndex | (value & maxEntryValue) >> endBitSubIndex; + } + } + return data; + } + + public static void iterateCompactArray(int bitsPerEntry, int entries, long[] data, BiIntConsumer consumer) { + long maxEntryValue = (1L << bitsPerEntry) - 1; + for (int i = 0; i < entries; i++) { + int bitIndex = i * bitsPerEntry; + int startIndex = bitIndex / 64; + int endIndex = ((i + 1) * bitsPerEntry - 1) / 64; + int startBitSubIndex = bitIndex % 64; + int val; + if (startIndex == endIndex) { + val = (int) (data[startIndex] >>> startBitSubIndex & maxEntryValue); + } else { + int endBitSubIndex = 64 - startBitSubIndex; + val = (int) ((data[startIndex] >>> startBitSubIndex | data[endIndex] << endBitSubIndex) & maxEntryValue); + } + consumer.consume(i, val); + } + } +}