From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Taiyou06 Date: Fri, 21 Feb 2025 18:05:09 +0100 Subject: [PATCH] Optimize LinearPalette diff --git a/net/minecraft/world/level/chunk/LinearPalette.java b/net/minecraft/world/level/chunk/LinearPalette.java index 2073f6ff41aa570102621d183ee890b076267d54..459b6adca18868354374d00f3da906395fb474ab 100644 --- a/net/minecraft/world/level/chunk/LinearPalette.java +++ b/net/minecraft/world/level/chunk/LinearPalette.java @@ -1,5 +1,6 @@ package net.minecraft.world.level.chunk; +import java.util.Arrays; import java.util.List; import java.util.function.Predicate; import net.minecraft.core.IdMap; @@ -10,6 +11,8 @@ import org.apache.commons.lang3.Validate; public class LinearPalette implements Palette, ca.spottedleaf.moonrise.patches.fast_palette.FastPalette { // Paper - optimise palette reads private final IdMap registry; private final T[] values; + private final int[] byteSizes; + private final int[] idCache; // Cached registry IDs for values private final PaletteResize resizeHandler; private final int bits; private int size; @@ -23,24 +26,34 @@ public class LinearPalette implements Palette, ca.spottedleaf.moonrise.pat private LinearPalette(IdMap registry, int bits, PaletteResize resizeHandler, List values) { this.registry = registry; - this.values = (T[])(new Object[1 << bits]); + this.values = (T[]) (new Object[1 << bits]); + this.idCache = new int[1 << bits]; + this.byteSizes = new int[1 << bits]; // Initialize byteSizes this.bits = bits; this.resizeHandler = resizeHandler; Validate.isTrue(values.size() <= this.values.length, "Can't initialize LinearPalette of size %d with %d entries", this.values.length, values.size()); for (int i = 0; i < values.size(); i++) { - this.values[i] = values.get(i); + T value = values.get(i); + this.values[i] = value; + int id = registry.getId(value); + this.idCache[i] = id; + this.byteSizes[i] = VarInt.getByteSize(id); // Precompute byte size } - this.size = values.size(); } - private LinearPalette(IdMap registry, T[] values, PaletteResize resizeHandler, int bits, int size) { + private LinearPalette(IdMap registry, T[] values, int[] idCache, PaletteResize resizeHandler, int bits, int size) { this.registry = registry; this.values = values; + this.idCache = idCache; this.resizeHandler = resizeHandler; this.bits = bits; this.size = size; + this.byteSizes = new int[idCache.length]; + for (int i = 0; i < idCache.length; i++) { + this.byteSizes[i] = VarInt.getByteSize(idCache[i]); + } } public static Palette create(int bits, IdMap registry, PaletteResize resizeHandler, List values) { @@ -58,6 +71,9 @@ public class LinearPalette implements Palette, ca.spottedleaf.moonrise.pat int ix = this.size; if (ix < this.values.length) { this.values[ix] = state; + int id = registry.getId(state); + this.idCache[ix] = id; + this.byteSizes[ix] = VarInt.getByteSize(id); // Cache byte size this.size++; return ix; } else { @@ -88,29 +104,28 @@ public class LinearPalette implements Palette, ca.spottedleaf.moonrise.pat @Override public void read(FriendlyByteBuf buffer) { this.size = buffer.readVarInt(); - for (int i = 0; i < this.size; i++) { - this.values[i] = this.registry.byIdOrThrow(buffer.readVarInt()); + int id = buffer.readVarInt(); + this.values[i] = this.registry.byIdOrThrow(id); + this.idCache[i] = id; + this.byteSizes[i] = VarInt.getByteSize(id); // Precompute during read } } @Override public void write(FriendlyByteBuf buffer) { buffer.writeVarInt(this.size); - for (int i = 0; i < this.size; i++) { - buffer.writeVarInt(this.registry.getId(this.values[i])); + buffer.writeVarInt(this.idCache[i]); // Use cached ID } } @Override public int getSerializedSize() { - int byteSize = VarInt.getByteSize(this.getSize()); - - for (int i = 0; i < this.getSize(); i++) { - byteSize += VarInt.getByteSize(this.registry.getId(this.values[i])); + int byteSize = VarInt.getByteSize(this.size); + for (int i = 0; i < this.size; i++) { + byteSize += this.byteSizes[i]; // Use cached byte sizes } - return byteSize; } @@ -121,6 +136,54 @@ public class LinearPalette implements Palette, ca.spottedleaf.moonrise.pat @Override public Palette copy(PaletteResize resizeHandler) { - return new LinearPalette<>(this.registry, (T[])((Object[])this.values.clone()), resizeHandler, this.bits, this.size); + // Special case for empty palette - fastest possible return + if (this.size == 0) { + return new LinearPalette<>(this.registry, (T[]) new Object[1], new int[1], resizeHandler, this.bits, 0); + } + + // For small sizes, allocate exact-sized arrays and use direct assignment + if (this.size <= 4) { + @SuppressWarnings("unchecked") + T[] valuesCopy = (T[]) new Object[this.size]; + int[] idCacheCopy = new int[this.size]; + + // Unrolled loop eliminates loop overhead for small arrays + switch (this.size) { + case 4: + valuesCopy[3] = this.values[3]; + idCacheCopy[3] = this.idCache[3]; + // Fall through + case 3: + valuesCopy[2] = this.values[2]; + idCacheCopy[2] = this.idCache[2]; + // Fall through + case 2: + valuesCopy[1] = this.values[1]; + idCacheCopy[1] = this.idCache[1]; + // Fall through + case 1: + valuesCopy[0] = this.values[0]; + idCacheCopy[0] = this.idCache[0]; + } + + return new LinearPalette<>(this.registry, valuesCopy, idCacheCopy, resizeHandler, this.bits, this.size); + } + + // For larger arrays, use optimized bulk operations + @SuppressWarnings("unchecked") + T[] valuesCopy = (T[]) new Object[this.size]; + int[] idCacheCopy = new int[this.size]; + + System.arraycopy(this.values, 0, valuesCopy, 0, this.size); + System.arraycopy(this.idCache, 0, idCacheCopy, 0, this.size); + + return new LinearPalette<>( + this.registry, + valuesCopy, + idCacheCopy, + resizeHandler, + this.bits, + this.size + ); } }