From 73093c0ff289c24b17efdc711b6d873ede52f931 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke Date: Thu, 16 Sep 2021 18:12:33 +0200 Subject: [PATCH] Read/write palette based on block/biome size variables --- .../viaversion/api/data/IntArrayMappings.java | 5 +++ .../viaversion/api/data/Mappings.java | 2 + .../api/data/entity/EntityTracker.java | 4 ++ .../api/minecraft/chunks/PaletteType.java | 12 ++++-- .../types/version/ChunkSectionType1_18.java | 15 +++++--- .../type/types/version/PaletteType1_18.java | 33 +++++++++-------- .../api/type/types/version/Types1_18.java | 3 -- .../data/entity/EntityTrackerBase.java | 11 ++++++ .../packets/EntityPackets.java | 1 + .../packets/WorldPackets.java | 5 ++- .../types/Chunk1_18Type.java | 13 +++++-- .../viaversion/rewriter/EntityRewriter.java | 10 +++++ .../viaversion/viaversion/util/MathUtil.java | 37 +++++++++++++++++++ 13 files changed, 120 insertions(+), 31 deletions(-) create mode 100644 common/src/main/java/com/viaversion/viaversion/util/MathUtil.java diff --git a/api/src/main/java/com/viaversion/viaversion/api/data/IntArrayMappings.java b/api/src/main/java/com/viaversion/viaversion/api/data/IntArrayMappings.java index fad8386de..c31c0b48b 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/data/IntArrayMappings.java +++ b/api/src/main/java/com/viaversion/viaversion/api/data/IntArrayMappings.java @@ -116,6 +116,11 @@ public class IntArrayMappings implements Mappings { oldToNew[id] = newId; } + @Override + public int size() { + return oldToNew.length; + } + public int[] getOldToNew() { return oldToNew; } diff --git a/api/src/main/java/com/viaversion/viaversion/api/data/Mappings.java b/api/src/main/java/com/viaversion/viaversion/api/data/Mappings.java index cbda2ab04..510667148 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/data/Mappings.java +++ b/api/src/main/java/com/viaversion/viaversion/api/data/Mappings.java @@ -40,4 +40,6 @@ public interface Mappings { * @throws IndexOutOfBoundsException if the unmapped id is invalid */ void setNewId(int id, int newId); + + int size(); } diff --git a/api/src/main/java/com/viaversion/viaversion/api/data/entity/EntityTracker.java b/api/src/main/java/com/viaversion/viaversion/api/data/entity/EntityTracker.java index 938007785..9f83372e6 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/data/entity/EntityTracker.java +++ b/api/src/main/java/com/viaversion/viaversion/api/data/entity/EntityTracker.java @@ -147,4 +147,8 @@ public interface EntityTracker { * @param currentWorld name of the current world */ void setCurrentWorld(String currentWorld); + + int biomesSent(); + + void setBiomesSent(int biomesSent); } diff --git a/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/PaletteType.java b/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/PaletteType.java index 1d863c8cc..8881b92aa 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/PaletteType.java +++ b/api/src/main/java/com/viaversion/viaversion/api/minecraft/chunks/PaletteType.java @@ -23,15 +23,21 @@ package com.viaversion.viaversion.api.minecraft.chunks; public enum PaletteType { - BLOCKS(8), - BIOMES(2); + BLOCKS(ChunkSection.SIZE, 8), + BIOMES(4 * 4 * 4, 2); + private final int maxSize; private final int highestBitsPerValue; - PaletteType(final int highestBitsPerValue) { + PaletteType(final int maxSize, final int highestBitsPerValue) { + this.maxSize = maxSize; this.highestBitsPerValue = highestBitsPerValue; } + public int maxSize() { + return maxSize; + } + public int highestBitsPerValue() { return highestBitsPerValue; } diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/version/ChunkSectionType1_18.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/version/ChunkSectionType1_18.java index bf0aaaa50..2cbaa69be 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/version/ChunkSectionType1_18.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/version/ChunkSectionType1_18.java @@ -30,23 +30,28 @@ import io.netty.buffer.ByteBuf; public final class ChunkSectionType1_18 extends Type { - public ChunkSectionType1_18() { + private final PaletteType1_18 blockPaletteType; + private final PaletteType1_18 biomePaletteType; + + public ChunkSectionType1_18(final int globalPaletteBlockBits, final int globalPaletteBiomeBits) { super("Chunk Section Type", ChunkSection.class); + this.blockPaletteType = new PaletteType1_18(PaletteType.BLOCKS, globalPaletteBlockBits); + this.biomePaletteType = new PaletteType1_18(PaletteType.BIOMES, globalPaletteBiomeBits); } @Override public ChunkSection read(final ByteBuf buffer) throws Exception { final ChunkSection chunkSection = new ChunkSectionImpl(); chunkSection.setNonAirBlocksCount(buffer.readShort()); - chunkSection.addPalette(PaletteType.BLOCKS, Types1_18.BLOCK_PALETTE_TYPE.read(buffer)); - chunkSection.addPalette(PaletteType.BIOMES, Types1_18.BIOME_PALETTE_TYPE.read(buffer)); + chunkSection.addPalette(PaletteType.BLOCKS, blockPaletteType.read(buffer)); + chunkSection.addPalette(PaletteType.BIOMES, biomePaletteType.read(buffer)); return chunkSection; } @Override public void write(final ByteBuf buffer, final ChunkSection section) throws Exception { buffer.writeShort(section.getNonAirBlocksCount()); - Types1_18.BLOCK_PALETTE_TYPE.write(buffer, section.palette(PaletteType.BLOCKS)); - Types1_18.BIOME_PALETTE_TYPE.write(buffer, section.palette(PaletteType.BIOMES)); + blockPaletteType.write(buffer, section.palette(PaletteType.BLOCKS)); + biomePaletteType.write(buffer, section.palette(PaletteType.BIOMES)); } } diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/version/PaletteType1_18.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/version/PaletteType1_18.java index d61663697..dbecfe7b3 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/version/PaletteType1_18.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/version/PaletteType1_18.java @@ -22,29 +22,30 @@ */ package com.viaversion.viaversion.api.type.types.version; -import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection; import com.viaversion.viaversion.api.minecraft.chunks.DataPalette; import com.viaversion.viaversion.api.minecraft.chunks.DataPaletteImpl; import com.viaversion.viaversion.api.minecraft.chunks.PaletteType; -import com.viaversion.viaversion.api.type.PartialType; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.util.CompactArrayUtil; import io.netty.buffer.ByteBuf; -public final class PaletteType1_18 extends PartialType { - private static final int GLOBAL_PALETTE = 15; +public final class PaletteType1_18 extends Type { + private final int globalPaletteBits; + private final PaletteType type; - public PaletteType1_18(final PaletteType type) { - super(type, DataPalette.class); + public PaletteType1_18(final PaletteType type, final int globalPaletteBits) { + super(DataPalette.class); + this.globalPaletteBits = globalPaletteBits; + this.type = type; } @Override - public DataPalette read(final ByteBuf buffer, final PaletteType type) throws Exception { + public DataPalette read(final ByteBuf buffer) throws Exception { int bitsPerValue = buffer.readByte(); final int originalBitsPerValue = bitsPerValue; if (bitsPerValue > type.highestBitsPerValue()) { - bitsPerValue = GLOBAL_PALETTE; + bitsPerValue = globalPaletteBits; } // Read palette @@ -57,7 +58,7 @@ public final class PaletteType1_18 extends PartialType return palette; } - if (bitsPerValue != GLOBAL_PALETTE) { + if (bitsPerValue != globalPaletteBits) { final int paletteLength = Type.VAR_INT.readPrimitive(buffer); palette = new DataPaletteImpl(paletteLength); for (int i = 0; i < paletteLength; i++) { @@ -71,7 +72,7 @@ public final class PaletteType1_18 extends PartialType final long[] values = new long[Type.VAR_INT.readPrimitive(buffer)]; if (values.length > 0) { final char valuesPerLong = (char) (64 / bitsPerValue); - final int expectedLength = (ChunkSection.SIZE + valuesPerLong - 1) / valuesPerLong; + final int expectedLength = (type.maxSize() + valuesPerLong - 1) / valuesPerLong; if (values.length != expectedLength) { throw new IllegalStateException("Palette data length (" + values.length + ") does not match expected length (" + expectedLength + ")! bitsPerValue=" + bitsPerValue + ", originalBitsPerValue=" + originalBitsPerValue); } @@ -79,14 +80,14 @@ public final class PaletteType1_18 extends PartialType for (int i = 0; i < values.length; i++) { values[i] = buffer.readLong(); } - CompactArrayUtil.iterateCompactArrayWithPadding(bitsPerValue, ChunkSection.SIZE, values, - bitsPerValue == GLOBAL_PALETTE ? palette::setIdAt : palette::setPaletteIndexAt); + CompactArrayUtil.iterateCompactArrayWithPadding(bitsPerValue, type.maxSize(), values, + bitsPerValue == globalPaletteBits ? palette::setIdAt : palette::setPaletteIndexAt); } return palette; } @Override - public void write(final ByteBuf buffer, final PaletteType type, final DataPalette palette) throws Exception { + public void write(final ByteBuf buffer, final DataPalette palette) throws Exception { int bitsPerValue; if (palette.size() > 1) { // 1, 2, and 3 bit linear palettes can't be read by the client @@ -96,7 +97,7 @@ public final class PaletteType1_18 extends PartialType } if (bitsPerValue > type.highestBitsPerValue()) { - bitsPerValue = GLOBAL_PALETTE; + bitsPerValue = globalPaletteBits; } } else { bitsPerValue = 0; @@ -111,7 +112,7 @@ public final class PaletteType1_18 extends PartialType return; } - if (bitsPerValue != GLOBAL_PALETTE) { + if (bitsPerValue != globalPaletteBits) { // Write pallete Type.VAR_INT.writePrimitive(buffer, palette.size()); for (int i = 0; i < palette.size(); i++) { @@ -119,7 +120,7 @@ public final class PaletteType1_18 extends PartialType } } - final long[] data = CompactArrayUtil.createCompactArrayWithPadding(bitsPerValue, ChunkSection.SIZE, bitsPerValue == GLOBAL_PALETTE ? palette::idAt : palette::paletteIndexAt); + final long[] data = CompactArrayUtil.createCompactArrayWithPadding(bitsPerValue, type.maxSize(), bitsPerValue == globalPaletteBits ? palette::idAt : palette::paletteIndexAt); Type.VAR_INT.writePrimitive(buffer, data.length); for (final long l : data) { buffer.writeLong(l); diff --git a/api/src/main/java/com/viaversion/viaversion/api/type/types/version/Types1_18.java b/api/src/main/java/com/viaversion/viaversion/api/type/types/version/Types1_18.java index ba2623fdb..b1a539c62 100644 --- a/api/src/main/java/com/viaversion/viaversion/api/type/types/version/Types1_18.java +++ b/api/src/main/java/com/viaversion/viaversion/api/type/types/version/Types1_18.java @@ -30,8 +30,5 @@ import com.viaversion.viaversion.api.type.Type; public final class Types1_18 { - public static final Type CHUNK_SECTION = new ChunkSectionType1_18(); public static final Type BLOCK_ENTITY = new BlockEntityType1_18(); - public static final Type BLOCK_PALETTE_TYPE = new PaletteType1_18(PaletteType.BLOCKS); - public static final Type BIOME_PALETTE_TYPE = new PaletteType1_18(PaletteType.BIOMES); } diff --git a/common/src/main/java/com/viaversion/viaversion/data/entity/EntityTrackerBase.java b/common/src/main/java/com/viaversion/viaversion/data/entity/EntityTrackerBase.java index 0a5741206..87183e713 100644 --- a/common/src/main/java/com/viaversion/viaversion/data/entity/EntityTrackerBase.java +++ b/common/src/main/java/com/viaversion/viaversion/data/entity/EntityTrackerBase.java @@ -38,6 +38,7 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis private int currentWorldSectionHeight = 16; private int currentMinY; private String currentWorld; + private int biomesSent = -1; public EntityTrackerBase(UserConnection connection, @Nullable EntityType playerType) { this(connection, playerType, false); @@ -147,4 +148,14 @@ public class EntityTrackerBase implements EntityTracker, ClientEntityIdChangeLis public void setCurrentWorld(final String currentWorld) { this.currentWorld = currentWorld; } + + @Override + public int biomesSent() { + return biomesSent; + } + + @Override + public void setBiomesSent(int biomesSent) { + this.biomesSent = biomesSent; + } } diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_18to1_17_1/packets/EntityPackets.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_18to1_17_1/packets/EntityPackets.java index 2312277c4..248bfabbc 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_18to1_17_1/packets/EntityPackets.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_18to1_17_1/packets/EntityPackets.java @@ -54,6 +54,7 @@ public final class EntityPackets extends EntityRewriter { map(Type.NBT); // Current dimension data map(Type.STRING); // World handler(worldDataTrackerHandler(1)); + handler(biomeSizeTracker()); } }); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_18to1_17_1/packets/WorldPackets.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_18to1_17_1/packets/WorldPackets.java index 57344e1ca..39c4d43bf 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_18to1_17_1/packets/WorldPackets.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_18to1_17_1/packets/WorldPackets.java @@ -38,6 +38,7 @@ import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.BlockEntityIds; import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.Protocol1_18To1_17_1; import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.storage.ChunkLightStorage; import com.viaversion.viaversion.protocols.protocol1_18to1_17_1.types.Chunk1_18Type; +import com.viaversion.viaversion.util.MathUtil; import java.util.ArrayList; import java.util.List; @@ -166,7 +167,9 @@ public final class WorldPackets { } final Chunk chunk = new Chunk1_18(oldChunk.getX(), oldChunk.getZ(), oldChunk.getSections(), oldChunk.getHeightMap(), blockEntities); - wrapper.write(new Chunk1_18Type(tracker.currentWorldSectionHeight()), chunk); + wrapper.write(new Chunk1_18Type(tracker.currentWorldSectionHeight(), + MathUtil.ceilLog2(protocol.getMappingData().getBlockStateMappings().size()), + MathUtil.ceilLog2(tracker.biomesSent())), chunk); // Get and remove light stored, there's only full chunk packets //TODO Only get, not remove if we find out people re-send full chunk packets without re-sending light final ChunkLightStorage lightStorage = wrapper.user().get(ChunkLightStorage.class); diff --git a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_18to1_17_1/types/Chunk1_18Type.java b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_18to1_17_1/types/Chunk1_18Type.java index 2b2d3c68c..d6c3df15e 100644 --- a/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_18to1_17_1/types/Chunk1_18Type.java +++ b/common/src/main/java/com/viaversion/viaversion/protocols/protocol1_18to1_17_1/types/Chunk1_18Type.java @@ -19,12 +19,14 @@ package com.viaversion.viaversion.protocols.protocol1_18to1_17_1.types; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.google.common.base.Preconditions; +import com.viaversion.viaversion.api.Via; import com.viaversion.viaversion.api.minecraft.blockentity.BlockEntity; import com.viaversion.viaversion.api.minecraft.chunks.Chunk; import com.viaversion.viaversion.api.minecraft.chunks.Chunk1_18; import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection; import com.viaversion.viaversion.api.type.Type; import com.viaversion.viaversion.api.type.types.minecraft.BaseChunkType; +import com.viaversion.viaversion.api.type.types.version.ChunkSectionType1_18; import com.viaversion.viaversion.api.type.types.version.Types1_18; import io.netty.buffer.ByteBuf; @@ -32,11 +34,13 @@ import java.util.ArrayList; import java.util.List; public final class Chunk1_18Type extends Type { + private final ChunkSectionType1_18 sectionType; private final int ySectionCount; - public Chunk1_18Type(final int ySectionCount) { + public Chunk1_18Type(final int ySectionCount, final int globalPaletteBlockBits, final int globalPaletteBiomeBits) { super(Chunk.class); Preconditions.checkArgument(ySectionCount > 0); + this.sectionType = new ChunkSectionType1_18(globalPaletteBlockBits, globalPaletteBiomeBits); this.ySectionCount = ySectionCount; } @@ -51,9 +55,12 @@ public final class Chunk1_18Type extends Type { final ChunkSection[] sections = new ChunkSection[ySectionCount]; try { for (int i = 0; i < ySectionCount; i++) { - sections[i] = Types1_18.CHUNK_SECTION.read(sectionsBuf); + sections[i] = sectionType.read(sectionsBuf); } } finally { + if (sectionsBuf.readableBytes() > 0) { + Via.getPlatform().getLogger().warning("Found " + sectionsBuf.readableBytes() + " more bytes than expected while reading the chunk: " + chunkX + "/" + chunkZ); + } sectionsBuf.release(); } @@ -76,7 +83,7 @@ public final class Chunk1_18Type extends Type { final ByteBuf sectionBuffer = buffer.alloc().buffer(); try { for (final ChunkSection section : chunk.getSections()) { - Types1_18.CHUNK_SECTION.write(sectionBuffer, section); + sectionType.write(sectionBuffer, section); } sectionBuffer.readerIndex(0); Type.VAR_INT.writePrimitive(buffer, sectionBuffer.readableBytes()); diff --git a/common/src/main/java/com/viaversion/viaversion/rewriter/EntityRewriter.java b/common/src/main/java/com/viaversion/viaversion/rewriter/EntityRewriter.java index 2634a2073..47320a65b 100644 --- a/common/src/main/java/com/viaversion/viaversion/rewriter/EntityRewriter.java +++ b/common/src/main/java/com/viaversion/viaversion/rewriter/EntityRewriter.java @@ -19,6 +19,7 @@ package com.viaversion.viaversion.rewriter; import com.github.steveice10.opennbt.tag.builtin.CompoundTag; import com.github.steveice10.opennbt.tag.builtin.IntTag; +import com.github.steveice10.opennbt.tag.builtin.ListTag; import com.github.steveice10.opennbt.tag.builtin.Tag; import com.google.common.base.Preconditions; import com.viaversion.viaversion.api.Via; @@ -397,6 +398,15 @@ public abstract class EntityRewriter extends RewriterBase }; } + public PacketHandler biomeSizeTracker() { + return wrapper -> { + final CompoundTag registry = wrapper.get(Type.NBT, 0); + final CompoundTag biomeRegistry = registry.get("minecraft:worldgen/biome"); + final ListTag biomes = biomeRegistry.get("value"); + tracker(wrapper.user()).setBiomesSent(biomes.size()); + }; + } + // --------------------------------------------------------------------------- // Sub 1.14.1 methods diff --git a/common/src/main/java/com/viaversion/viaversion/util/MathUtil.java b/common/src/main/java/com/viaversion/viaversion/util/MathUtil.java new file mode 100644 index 000000000..86f0d99a4 --- /dev/null +++ b/common/src/main/java/com/viaversion/viaversion/util/MathUtil.java @@ -0,0 +1,37 @@ +/* + * This file is part of ViaVersion - https://github.com/ViaVersion/ViaVersion + * Copyright (C) 2016-2021 ViaVersion and contributors + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +package com.viaversion.viaversion.util; + +public final class MathUtil { + + /** + * Primitive method to return the ceiled log to the base of 2 for the given number. + * + * @param i number to ceillog + * @return ceiled log2 of the given number + */ + public static int ceilLog2(final int i) { + int j = 1; + int k = 0; + while (j < i) { + j *= 2; + k++; + } + return k; + } +}