3
0
Mirror von https://github.com/ViaVersion/ViaVersion.git synchronisiert 2024-12-26 16:12:42 +01:00

Don't allocate bufs in 1.18/1.20 chunk types

Unlike Mojang, we don't sneak a byte array of data outside of the actual packet reading, so there's no reason to not just use the original buffer.
Slicing doesn't allocate anything while also setting the reader index correctly, as also used in the previous types
Dieser Commit ist enthalten in:
Nassim Jahnke 2024-11-05 12:03:16 +01:00
Ursprung 77f0826ec8
Commit deab6a0cac
Es konnte kein GPG-Schlüssel zu dieser Signatur gefunden werden
GPG-Schlüssel-ID: EF6771C01F6EF02F
5 geänderte Dateien mit 73 neuen und 50 gelöschten Zeilen

Datei anzeigen

@ -32,6 +32,15 @@ public class VarIntType extends Type<Integer> implements TypeConverter<Integer>
private static final int VALUE_BITS = 0x7F;
private static final int MULTI_BYTE_BITS = ~VALUE_BITS;
private static final int MAX_BYTES = 5;
private static final int[] VAR_INT_LENGTHS = new int[65];
static {
// Copied from Velocity https://github.com/PaperMC/Velocity/blob/08a42b3723633ea5eb6b96c0bb42180f3c2b07eb/proxy/src/main/java/com/velocitypowered/proxy/protocol/ProtocolUtils.java#L166
for (int i = 0; i <= 32; ++i) {
VAR_INT_LENGTHS[i] = (int) Math.ceil((31d - (i - 1)) / 7d);
}
VAR_INT_LENGTHS[32] = 1; // Special case for the number 0.
}
public VarIntType() {
super("VarInt", Integer.class);
@ -61,15 +70,6 @@ public class VarIntType extends Type<Integer> implements TypeConverter<Integer>
buffer.writeByte(value);
}
public static int varIntLength(int value) {
int length = 1;
while ((value & MULTI_BYTE_BITS) != 0) {
length++;
value >>>= 7;
}
return length;
}
/**
* @deprecated use {@link #readPrimitive(ByteBuf)} for manual reading to avoid wrapping
*/
@ -97,4 +97,8 @@ public class VarIntType extends Type<Integer> implements TypeConverter<Integer>
}
throw new UnsupportedOperationException();
}
public static int varIntLength(final int value) {
return VAR_INT_LENGTHS[Integer.numberOfLeadingZeros(value)];
}
}

Datei anzeigen

@ -22,6 +22,7 @@
*/
package com.viaversion.viaversion.api.type.types.chunk;
import com.viaversion.viaversion.api.minecraft.chunks.Chunk;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSection;
import com.viaversion.viaversion.api.minecraft.chunks.ChunkSectionImpl;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
@ -54,4 +55,14 @@ public final class ChunkSectionType1_18 extends Type<ChunkSection> {
blockPaletteType.write(buffer, section.palette(PaletteType.BLOCKS));
biomePaletteType.write(buffer, section.palette(PaletteType.BIOMES));
}
public int serializedSize(final Chunk chunk) {
int length = 0;
for (final ChunkSection section : chunk.getSections()) {
length += Short.BYTES
+ blockPaletteType.serializedSize(section.palette(PaletteType.BLOCKS))
+ biomePaletteType.serializedSize(section.palette(PaletteType.BIOMES));
}
return length;
}
}

Datei anzeigen

@ -52,15 +52,11 @@ public final class ChunkType1_18 extends Type<Chunk> {
final CompoundTag heightMap = Types.NAMED_COMPOUND_TAG.read(buffer);
// Read sections
final ByteBuf sectionsBuf = buffer.readBytes(Types.VAR_INT.readPrimitive(buffer));
final ByteBuf sectionsBuf = buffer.readSlice(Types.VAR_INT.readPrimitive(buffer));
final ChunkSection[] sections = new ChunkSection[ySectionCount];
try {
for (int i = 0; i < ySectionCount; i++) {
sections[i] = sectionType.read(sectionsBuf);
}
} finally {
sectionsBuf.release();
}
final int blockEntitiesLength = Types.VAR_INT.readPrimitive(buffer);
final List<BlockEntity> blockEntities = new ArrayList<>(blockEntitiesLength);
@ -78,16 +74,9 @@ public final class ChunkType1_18 extends Type<Chunk> {
Types.NAMED_COMPOUND_TAG.write(buffer, chunk.getHeightMap());
final ByteBuf sectionBuffer = buffer.alloc().buffer();
try {
Types.VAR_INT.writePrimitive(buffer, sectionType.serializedSize(chunk));
for (final ChunkSection section : chunk.getSections()) {
sectionType.write(sectionBuffer, section);
}
sectionBuffer.readerIndex(0);
Types.VAR_INT.writePrimitive(buffer, sectionBuffer.readableBytes());
buffer.writeBytes(sectionBuffer);
} finally {
sectionBuffer.release(); // release buffer
sectionType.write(buffer, section);
}
Types.VAR_INT.writePrimitive(buffer, chunk.blockEntities().size());

Datei anzeigen

@ -52,15 +52,11 @@ public final class ChunkType1_20_2 extends Type<Chunk> {
final CompoundTag heightMap = Types.COMPOUND_TAG.read(buffer);
// Read sections
final ByteBuf sectionsBuf = buffer.readBytes(Types.VAR_INT.readPrimitive(buffer));
final ByteBuf sectionsBuf = buffer.readSlice(Types.VAR_INT.readPrimitive(buffer));
final ChunkSection[] sections = new ChunkSection[ySectionCount];
try {
for (int i = 0; i < ySectionCount; i++) {
sections[i] = sectionType.read(sectionsBuf);
}
} finally {
sectionsBuf.release();
}
final int blockEntitiesLength = Types.VAR_INT.readPrimitive(buffer);
final List<BlockEntity> blockEntities = new ArrayList<>(blockEntitiesLength);
@ -78,16 +74,9 @@ public final class ChunkType1_20_2 extends Type<Chunk> {
Types.COMPOUND_TAG.write(buffer, chunk.getHeightMap());
final ByteBuf sectionBuffer = buffer.alloc().buffer();
try {
Types.VAR_INT.writePrimitive(buffer, sectionType.serializedSize(chunk));
for (final ChunkSection section : chunk.getSections()) {
sectionType.write(sectionBuffer, section);
}
sectionBuffer.readerIndex(0);
Types.VAR_INT.writePrimitive(buffer, sectionBuffer.readableBytes());
buffer.writeBytes(sectionBuffer);
} finally {
sectionBuffer.release(); // release buffer
sectionType.write(buffer, section);
}
Types.VAR_INT.writePrimitive(buffer, chunk.blockEntities().size());

Datei anzeigen

@ -27,6 +27,7 @@ import com.viaversion.viaversion.api.minecraft.chunks.DataPaletteImpl;
import com.viaversion.viaversion.api.minecraft.chunks.PaletteType;
import com.viaversion.viaversion.api.type.Type;
import com.viaversion.viaversion.api.type.Types;
import com.viaversion.viaversion.api.type.types.VarIntType;
import com.viaversion.viaversion.util.CompactArrayUtil;
import com.viaversion.viaversion.util.MathUtil;
import io.netty.buffer.ByteBuf;
@ -94,13 +95,7 @@ public final class PaletteType1_18 extends Type<DataPalette> {
return;
}
// 1, 2, and 3 bit linear block palettes can't be read by the client
final int min = type == PaletteType.BLOCKS ? 4 : 1;
int bitsPerValue = Math.max(min, MathUtil.ceilLog2(size));
if (bitsPerValue > type.highestBitsPerValue()) {
bitsPerValue = globalPaletteBits;
}
final int bitsPerValue = bitsPerValue(size);
buffer.writeByte(bitsPerValue);
if (bitsPerValue != globalPaletteBits) {
@ -113,4 +108,39 @@ public final class PaletteType1_18 extends Type<DataPalette> {
Types.LONG_ARRAY_PRIMITIVE.write(buffer, CompactArrayUtil.createCompactArrayWithPadding(bitsPerValue, type.size(), bitsPerValue == globalPaletteBits ? palette::idAt : palette::paletteIndexAt));
}
private int bitsPerValue(final int size) {
// 1, 2, and 3 bit linear block palettes can't be read by the client
final int min = type == PaletteType.BLOCKS ? 4 : 1;
int bitsPerValue = Math.max(min, MathUtil.ceilLog2(size));
if (bitsPerValue > type.highestBitsPerValue()) {
bitsPerValue = globalPaletteBits;
}
return bitsPerValue;
}
public int serializedSize(final DataPalette palette) {
// This is a bit of extra work, but worth it to avoid otherwise having to allocate and write to an extra buffer.
// On top of saving memory, it provides small but measurable speedup compared to writing to a separate buffer and then back
final int size = palette.size();
final int bitsPerValue = bitsPerValue(size);
int serializedTypesSize = 0;
int serializedValuesSize = 1; // At least one byte for 0 length
if (size == 1) {
serializedTypesSize = VarIntType.varIntLength(palette.idByIndex(0));
} else {
if (bitsPerValue != globalPaletteBits) {
serializedTypesSize = VarIntType.varIntLength(size);
for (int i = 0; i < size; i++) {
serializedTypesSize += VarIntType.varIntLength(palette.idByIndex(i));
}
}
final int valuesPerLong = 64 / bitsPerValue;
final int values = (type.size() + valuesPerLong - 1) / valuesPerLong;
serializedValuesSize = VarIntType.varIntLength(values) + (Long.BYTES * values);
}
return Byte.BYTES + serializedTypesSize + serializedValuesSize;
}
}