Read/write palette based on block/biome size variables

This commit is contained in:
Nassim Jahnke 2021-09-16 18:12:33 +02:00
parent c5e27b89af
commit 73093c0ff2
No known key found for this signature in database
GPG Key ID: 6BE3B555EBC5982B
13 changed files with 120 additions and 31 deletions

View File

@ -116,6 +116,11 @@ public class IntArrayMappings implements Mappings {
oldToNew[id] = newId;
}
@Override
public int size() {
return oldToNew.length;
}
public int[] getOldToNew() {
return oldToNew;
}

View File

@ -40,4 +40,6 @@ public interface Mappings {
* @throws IndexOutOfBoundsException if the unmapped id is invalid
*/
void setNewId(int id, int newId);
int size();
}

View File

@ -147,4 +147,8 @@ public interface EntityTracker {
* @param currentWorld name of the current world
*/
void setCurrentWorld(String currentWorld);
int biomesSent();
void setBiomesSent(int biomesSent);
}

View File

@ -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;
}

View File

@ -30,23 +30,28 @@ import io.netty.buffer.ByteBuf;
public final class ChunkSectionType1_18 extends Type<ChunkSection> {
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));
}
}

View File

@ -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<DataPalette, PaletteType> {
private static final int GLOBAL_PALETTE = 15;
public final class PaletteType1_18 extends Type<DataPalette> {
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<DataPalette, PaletteType>
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<DataPalette, PaletteType>
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<DataPalette, PaletteType>
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<DataPalette, PaletteType>
}
if (bitsPerValue > type.highestBitsPerValue()) {
bitsPerValue = GLOBAL_PALETTE;
bitsPerValue = globalPaletteBits;
}
} else {
bitsPerValue = 0;
@ -111,7 +112,7 @@ public final class PaletteType1_18 extends PartialType<DataPalette, PaletteType>
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<DataPalette, PaletteType>
}
}
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);

View File

@ -30,8 +30,5 @@ import com.viaversion.viaversion.api.type.Type;
public final class Types1_18 {
public static final Type<ChunkSection> CHUNK_SECTION = new ChunkSectionType1_18();
public static final Type<BlockEntity> BLOCK_ENTITY = new BlockEntityType1_18();
public static final Type<DataPalette> BLOCK_PALETTE_TYPE = new PaletteType1_18(PaletteType.BLOCKS);
public static final Type<DataPalette> BIOME_PALETTE_TYPE = new PaletteType1_18(PaletteType.BIOMES);
}

View File

@ -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;
}
}

View File

@ -54,6 +54,7 @@ public final class EntityPackets extends EntityRewriter<Protocol1_18To1_17_1> {
map(Type.NBT); // Current dimension data
map(Type.STRING); // World
handler(worldDataTrackerHandler(1));
handler(biomeSizeTracker());
}
});

View File

@ -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);

View File

@ -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<Chunk> {
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<Chunk> {
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<Chunk> {
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());

View File

@ -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<T extends Protocol> extends RewriterBase<T>
};
}
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

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
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;
}
}