diff --git a/patches/server/0039-Gale-Faster-chunk-serialization.patch b/patches/server/0039-Gale-Faster-chunk-serialization.patch deleted file mode 100644 index b263b78..0000000 --- a/patches/server/0039-Gale-Faster-chunk-serialization.patch +++ /dev/null @@ -1,428 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: MrHua269 -Date: Wed, 31 Jul 2024 13:42:17 +0800 -Subject: [PATCH] Gale Faster chunk serialization - - -diff --git a/src/main/java/me/jellysquid/mods/lithium/common/world/chunk/LithiumHashPalette.java b/src/main/java/me/jellysquid/mods/lithium/common/world/chunk/LithiumHashPalette.java -new file mode 100644 -index 0000000000000000000000000000000000000000..349618b7f544bf9a30e0796d4d9a26407a2b8329 ---- /dev/null -+++ b/src/main/java/me/jellysquid/mods/lithium/common/world/chunk/LithiumHashPalette.java -@@ -0,0 +1,192 @@ -+// Gale - Lithium - faster chunk serialization -+ -+package me.jellysquid.mods.lithium.common.world.chunk; -+ -+import com.google.common.collect.ImmutableList; -+import it.unimi.dsi.fastutil.HashCommon; -+import it.unimi.dsi.fastutil.objects.Reference2IntMap; -+import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap; -+import java.util.Arrays; -+import java.util.List; -+import java.util.function.Predicate; -+import net.minecraft.core.IdMap; -+import net.minecraft.network.FriendlyByteBuf; -+import net.minecraft.network.VarInt; -+import net.minecraft.world.level.chunk.Palette; -+import net.minecraft.world.level.chunk.PaletteResize; -+ -+import static it.unimi.dsi.fastutil.Hash.FAST_LOAD_FACTOR; -+ -+/** -+ * Generally provides better performance over the vanilla {@link net.minecraft.world.level.chunk.HashMapPalette} when calling -+ * {@link LithiumHashPalette#idFor(Object)} through using a faster backing map and reducing pointer chasing. -+ */ -+public class LithiumHashPalette implements Palette { -+ private static final int ABSENT_VALUE = -1; -+ -+ private final IdMap idList; -+ private final PaletteResize resizeHandler; -+ private final int indexBits; -+ -+ private final Reference2IntMap table; -+ private T[] entries; -+ private int size = 0; -+ -+ public LithiumHashPalette(IdMap idList, PaletteResize resizeHandler, int indexBits, T[] entries, Reference2IntMap table, int size) { -+ this.idList = idList; -+ this.resizeHandler = resizeHandler; -+ this.indexBits = indexBits; -+ this.entries = entries; -+ this.table = table; -+ this.size = size; -+ } -+ -+ public LithiumHashPalette(IdMap idList, int bits, PaletteResize resizeHandler, List list) { -+ this(idList, bits, resizeHandler); -+ -+ for (T t : list) { -+ this.addEntry(t); -+ } -+ } -+ -+ @SuppressWarnings("unchecked") -+ public LithiumHashPalette(IdMap idList, int bits, PaletteResize resizeHandler) { -+ this.idList = idList; -+ this.indexBits = bits; -+ this.resizeHandler = resizeHandler; -+ -+ int capacity = 1 << bits; -+ -+ this.entries = (T[]) new Object[capacity]; -+ this.table = new Reference2IntOpenHashMap<>(capacity, FAST_LOAD_FACTOR); -+ this.table.defaultReturnValue(ABSENT_VALUE); -+ } -+ -+ @Override -+ public int idFor(T obj) { -+ int id = this.table.getInt(obj); -+ -+ if (id == ABSENT_VALUE) { -+ id = this.computeEntry(obj); -+ } -+ -+ return id; -+ } -+ -+ @Override -+ public boolean maybeHas(Predicate predicate) { -+ for (int i = 0; i < this.size; ++i) { -+ if (predicate.test(this.entries[i])) { -+ return true; -+ } -+ } -+ -+ return false; -+ } -+ -+ private int computeEntry(T obj) { -+ int id = this.addEntry(obj); -+ -+ if (id >= 1 << this.indexBits) { -+ if (this.resizeHandler == null) { -+ throw new IllegalStateException("Cannot grow"); -+ } else { -+ id = this.resizeHandler.onResize(this.indexBits + 1, obj); -+ } -+ } -+ -+ return id; -+ } -+ -+ private int addEntry(T obj) { -+ int nextId = this.size; -+ -+ if (nextId >= this.entries.length) { -+ this.resize(this.size); -+ } -+ -+ this.table.put(obj, nextId); -+ this.entries[nextId] = obj; -+ -+ this.size++; -+ -+ return nextId; -+ } -+ -+ private void resize(int neededCapacity) { -+ this.entries = Arrays.copyOf(this.entries, HashCommon.nextPowerOfTwo(neededCapacity + 1)); -+ } -+ -+ @Override -+ public T valueFor(int id) { -+ T[] entries = this.entries; -+ -+ if (id >= 0 && id < entries.length) { -+ return entries[id]; -+ } -+ -+ return null; -+ } -+ -+ @Override -+ public void read(FriendlyByteBuf buf) { -+ this.clear(); -+ -+ int entryCount = buf.readVarInt(); -+ -+ for (int i = 0; i < entryCount; ++i) { -+ this.addEntry(this.idList.byId(buf.readVarInt())); -+ } -+ } -+ -+ @Override -+ public void write(FriendlyByteBuf buf) { -+ int size = this.size; -+ buf.writeVarInt(size); -+ -+ for (int i = 0; i < size; ++i) { -+ buf.writeVarInt(this.idList.getId(this.valueFor(i))); -+ } -+ } -+ -+ @Override -+ public int getSerializedSize() { -+ int size = VarInt.getByteSize(this.size); -+ -+ for (int i = 0; i < this.size; ++i) { -+ size += VarInt.getByteSize(this.idList.getId(this.valueFor(i))); -+ } -+ -+ return size; -+ } -+ -+ @Override -+ public int getSize() { -+ return this.size; -+ } -+ -+ @Override -+ public Palette copy() { -+ return new LithiumHashPalette<>(this.idList, this.resizeHandler, this.indexBits, this.entries.clone(), new Reference2IntOpenHashMap<>(this.table), this.size); -+ } -+ -+ private void clear() { -+ Arrays.fill(this.entries, null); -+ this.table.clear(); -+ this.size = 0; -+ } -+ -+ public List getElements() { -+ ImmutableList.Builder builder = new ImmutableList.Builder<>(); -+ for (T entry : this.entries) { -+ if (entry != null) { -+ builder.add(entry); -+ } -+ } -+ return builder.build(); -+ } -+ -+ public static Palette create(int bits, IdMap idList, PaletteResize listener, List list) { -+ return new LithiumHashPalette<>(idList, bits, listener, list); -+ } -+} -diff --git a/src/main/java/net/minecraft/util/BitStorage.java b/src/main/java/net/minecraft/util/BitStorage.java -index e4e153cb8899e70273aa150b8ea26907cf68b15c..6bfd2ff3318085b0204bb4235ba9f3df2e981087 100644 ---- a/src/main/java/net/minecraft/util/BitStorage.java -+++ b/src/main/java/net/minecraft/util/BitStorage.java -@@ -21,6 +21,8 @@ public interface BitStorage extends ca.spottedleaf.moonrise.patches.block_counti - - BitStorage copy(); - -+ void compact(net.minecraft.world.level.chunk.Palette srcPalette, net.minecraft.world.level.chunk.Palette dstPalette, short[] out); // Gale - Lithium - faster chunk serialization -+ - // Paper start - block counting - // provide default impl in case mods implement this... - @Override -diff --git a/src/main/java/net/minecraft/util/SimpleBitStorage.java b/src/main/java/net/minecraft/util/SimpleBitStorage.java -index d99ec470b4653beab630999a5b2c1a6428b20c38..f8640b8cce9018d877ec69bbba241d5d9e89b8d8 100644 ---- a/src/main/java/net/minecraft/util/SimpleBitStorage.java -+++ b/src/main/java/net/minecraft/util/SimpleBitStorage.java -@@ -472,4 +472,45 @@ public class SimpleBitStorage implements BitStorage { - super(message); - } - } -+ -+ // Gale start - Lithium - faster chunk serialization -+ @Override -+ public void compact(net.minecraft.world.level.chunk.Palette srcPalette, net.minecraft.world.level.chunk.Palette dstPalette, short[] out) { -+ if (this.size >= Short.MAX_VALUE) { -+ throw new IllegalStateException("Array too large"); -+ } -+ -+ if (this.size != out.length) { -+ throw new IllegalStateException("Array size mismatch"); -+ } -+ -+ short[] mappings = new short[(int) (this.mask + 1)]; -+ -+ int idx = 0; -+ -+ for (long word : this.data) { -+ long bits = word; -+ -+ for (int elementIdx = 0; elementIdx < this.valuesPerLong; ++elementIdx) { -+ int value = (int) (bits & this.mask); -+ int remappedId = mappings[value]; -+ -+ if (remappedId == 0) { -+ remappedId = dstPalette.idFor(srcPalette.valueFor(value)) + 1; -+ mappings[value] = (short) remappedId; -+ } -+ -+ out[idx] = (short) (remappedId - 1); -+ bits >>= this.bits; -+ -+ ++idx; -+ -+ if (idx >= this.size) { -+ return; -+ } -+ } -+ } -+ } -+ // Gale end - Lithium - faster chunk serialization -+ - } -diff --git a/src/main/java/net/minecraft/util/ZeroBitStorage.java b/src/main/java/net/minecraft/util/ZeroBitStorage.java -index 1f9c436a632e4f110be61cf76fcfc3b7eb80334e..3e57421c045851413998e4e181793c739419c85a 100644 ---- a/src/main/java/net/minecraft/util/ZeroBitStorage.java -+++ b/src/main/java/net/minecraft/util/ZeroBitStorage.java -@@ -12,6 +12,8 @@ public class ZeroBitStorage implements BitStorage { - this.size = size; - } - -+ @Override public void compact(net.minecraft.world.level.chunk.Palette srcPalette, net.minecraft.world.level.chunk.Palette dstPalette, short[] out) {} // Gale - Lithium - faster chunk serialization -+ - @Override - public final int getAndSet(int index, int value) { // Paper - Perf: Optimize SimpleBitStorage - //Validate.inclusiveBetween(0L, (long)(this.size - 1), (long)index); // Paper - Perf: Optimize SimpleBitStorage -diff --git a/src/main/java/net/minecraft/world/level/chunk/PaletteResize.java b/src/main/java/net/minecraft/world/level/chunk/PaletteResize.java -index acae3eb30e0689048937f479dc3070f0688abdad..4b79f0474a9013dd4fdb68c6363ca1942ba8b007 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/PaletteResize.java -+++ b/src/main/java/net/minecraft/world/level/chunk/PaletteResize.java -@@ -1,5 +1,5 @@ - package net.minecraft.world.level.chunk; - --interface PaletteResize { -+public interface PaletteResize { // Gale - Lithium - faster chunk serialization - package -> public - int onResize(int newBits, T object); - } -diff --git a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java -index 8b84bf2272556ac3321cbf16361d7f48a1cc6873..8dd0813c6b00badf38a0d7f08572e8f68b4034be 100644 ---- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java -+++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java -@@ -25,6 +25,22 @@ import net.minecraft.util.ThreadingDetector; - import net.minecraft.util.ZeroBitStorage; - - public class PalettedContainer implements PaletteResize, PalettedContainerRO { -+ -+ // Gale start - Lithium - faster chunk serialization -+ private static final ThreadLocal CACHED_ARRAY_4096 = ThreadLocal.withInitial(() -> new short[4096]); -+ private static final ThreadLocal CACHED_ARRAY_64 = ThreadLocal.withInitial(() -> new short[64]); -+ private Optional asOptional(long[] data) { -+ return Optional.of(Arrays.stream(data)); -+ } -+ private short[] getOrCreate(int size) { -+ return switch (size) { -+ case 64 -> CACHED_ARRAY_64.get(); -+ case 4096 -> CACHED_ARRAY_4096.get(); -+ default -> new short[size]; -+ }; -+ } -+ // Gale end - Lithium - faster chunk serialization -+ - private static final int MIN_PALETTE_BITS = 0; - private final PaletteResize dummyPaletteResize = (newSize, added) -> 0; - public final IdMap registry; -@@ -348,28 +364,54 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - public synchronized PalettedContainerRO.PackedData pack(IdMap idList, PalettedContainer.Strategy paletteProvider) { // Paper - synchronize - this.acquire(); - -- PalettedContainerRO.PackedData var12; -+ // Gale start - Lithium - faster chunk serialization -+ Optional data = Optional.empty(); -+ List elements = null; - try { -- HashMapPalette hashMapPalette = new HashMapPalette<>(idList, this.data.storage.getBits(), this.dummyPaletteResize); -- int i = paletteProvider.size(); -- int[] is = new int[i]; -- this.data.storage.unpack(is); -- swapPalette(is, id -> hashMapPalette.idFor(this.data.palette.valueFor(id))); -- int j = paletteProvider.calculateBitsForSerialization(idList, hashMapPalette.getSize()); -- Optional optional; -- if (j != 0) { -- SimpleBitStorage simpleBitStorage = new SimpleBitStorage(j, i, is); -- optional = Optional.of(Arrays.stream(simpleBitStorage.getRaw())); -- } else { -- optional = Optional.empty(); -+ // The palette that will be serialized -+ me.jellysquid.mods.lithium.common.world.chunk.LithiumHashPalette hashPalette = null; -+ -+ final Palette palette = this.data.palette(); -+ final BitStorage storage = this.data.storage(); -+ if (storage instanceof ZeroBitStorage || palette.getSize() == 1) { -+ // If the palette only contains one entry, don't attempt to repack it. -+ elements = List.of(palette.valueFor(0)); -+ } else if (palette instanceof me.jellysquid.mods.lithium.common.world.chunk.LithiumHashPalette lithiumHashPalette) { -+ hashPalette = lithiumHashPalette; - } - -- var12 = new PalettedContainerRO.PackedData<>(hashMapPalette.getEntries(), optional); -+ if (elements == null) { -+ me.jellysquid.mods.lithium.common.world.chunk.LithiumHashPalette compactedPalette = new me.jellysquid.mods.lithium.common.world.chunk.LithiumHashPalette<>(idList, storage.getBits(), this.dummyPaletteResize); -+ short[] array = this.getOrCreate(paletteProvider.size()); -+ -+ storage.compact(this.data.palette(), compactedPalette, array); -+ -+ // If the palette didn't change during compaction, do a simple copy of the data array -+ if (hashPalette != null && hashPalette.getSize() == compactedPalette.getSize() && storage.getBits() == paletteProvider.calculateBitsForSerialization(idList, hashPalette.getSize())) { // paletteSize can de-sync from palette - see https://github.com/CaffeineMC/lithium-fabric/issues/279 -+ data = this.asOptional(storage.getRaw().clone()); -+ elements = hashPalette.getElements(); -+ } else { -+ int bits = paletteProvider.calculateBitsForSerialization(idList, compactedPalette.getSize()); -+ if (bits != 0) { -+ // Re-pack the integer array as the palette has changed size -+ SimpleBitStorage copy = new SimpleBitStorage(bits, array.length); -+ for (int i = 0; i < array.length; ++i) { -+ copy.set(i, array[i]); -+ } -+ -+ // We don't need to clone the data array as we are the sole owner of it -+ data = this.asOptional(copy.getRaw()); -+ } -+ -+ elements = compactedPalette.getElements(); -+ } -+ } - } finally { - this.release(); - } - -- return var12; -+ return new PalettedContainerRO.PackedData<>(elements, data); -+ // Gale end - Lithium - faster chunk serialization - } - - private static void swapPalette(int[] is, IntUnaryOperator applier) { -@@ -409,13 +451,33 @@ public class PalettedContainer implements PaletteResize, PalettedContainer - - @Override - public void count(PalettedContainer.CountConsumer counter) { -- if (this.data.palette.getSize() == 1) { -- counter.accept(this.data.palette.valueFor(0), this.data.storage.getSize()); -- } else { -- Int2IntOpenHashMap int2IntOpenHashMap = new Int2IntOpenHashMap(); -- this.data.storage.getAll(key -> int2IntOpenHashMap.addTo(key, 1)); -- int2IntOpenHashMap.int2IntEntrySet().forEach(entry -> counter.accept(this.data.palette.valueFor(entry.getIntKey()), entry.getIntValue())); -+ // Gale start - Lithium - faster chunk serialization -+ int len = this.data.palette().getSize(); -+ -+ // Do not allocate huge arrays if we're using a large palette -+ if (len > 4096) { -+ // VanillaCopy -+ if (this.data.palette.getSize() == 1) { -+ counter.accept(this.data.palette.valueFor(0), this.data.storage.getSize()); -+ } else { -+ Int2IntOpenHashMap int2IntOpenHashMap = new Int2IntOpenHashMap(); -+ this.data.storage.getAll(key -> int2IntOpenHashMap.addTo(key, 1)); -+ int2IntOpenHashMap.int2IntEntrySet().forEach(entry -> counter.accept(this.data.palette.valueFor(entry.getIntKey()), entry.getIntValue())); -+ } -+ } -+ -+ short[] counts = new short[len]; -+ -+ this.data.storage().getAll(i -> counts[i]++); -+ -+ for (int i = 0; i < counts.length; i++) { -+ T obj = this.data.palette().valueFor(i); -+ -+ if (obj != null) { -+ counter.accept(obj, counts[i]); -+ } - } -+ // Gale end - Lithium - faster chunk serialization - } - - static record Configuration(Palette.Factory factory, int bits) { diff --git a/patches/server/0040-Gale-Reduce-lambda-and-Optional-allocation-in-Entity.patch b/patches/server/0039-Gale-Reduce-lambda-and-Optional-allocation-in-Entity.patch similarity index 100% rename from patches/server/0040-Gale-Reduce-lambda-and-Optional-allocation-in-Entity.patch rename to patches/server/0039-Gale-Reduce-lambda-and-Optional-allocation-in-Entity.patch diff --git a/patches/server/0041-Gale-Replace-throttle-tracker-map-with-optimized-col.patch b/patches/server/0040-Gale-Replace-throttle-tracker-map-with-optimized-col.patch similarity index 100% rename from patches/server/0041-Gale-Replace-throttle-tracker-map-with-optimized-col.patch rename to patches/server/0040-Gale-Replace-throttle-tracker-map-with-optimized-col.patch diff --git a/patches/server/0042-Gale-Skip-entity-move-if-movement-is-zero.patch b/patches/server/0041-Gale-Skip-entity-move-if-movement-is-zero.patch similarity index 100% rename from patches/server/0042-Gale-Skip-entity-move-if-movement-is-zero.patch rename to patches/server/0041-Gale-Skip-entity-move-if-movement-is-zero.patch diff --git a/patches/server/0043-Sparkly-Paper-Optimize-canSee-checks.patch b/patches/server/0042-Sparkly-Paper-Optimize-canSee-checks.patch similarity index 100% rename from patches/server/0043-Sparkly-Paper-Optimize-canSee-checks.patch rename to patches/server/0042-Sparkly-Paper-Optimize-canSee-checks.patch diff --git a/patches/server/0044-SparklyPaper-Skip-MapItem-update-if-the-map-does-not.patch b/patches/server/0043-SparklyPaper-Skip-MapItem-update-if-the-map-does-not.patch similarity index 100% rename from patches/server/0044-SparklyPaper-Skip-MapItem-update-if-the-map-does-not.patch rename to patches/server/0043-SparklyPaper-Skip-MapItem-update-if-the-map-does-not.patch diff --git a/patches/server/0045-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch b/patches/server/0044-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch similarity index 100% rename from patches/server/0045-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch rename to patches/server/0044-SparklyPaper-Skip-distanceToSqr-call-in-ServerEntity.patch diff --git a/patches/server/0046-Leaf-Skip-event-if-no-listeners.patch b/patches/server/0045-Leaf-Skip-event-if-no-listeners.patch similarity index 100% rename from patches/server/0046-Leaf-Skip-event-if-no-listeners.patch rename to patches/server/0045-Leaf-Skip-event-if-no-listeners.patch diff --git a/patches/server/0047-Purpur-use-alternative-keep-alive.patch b/patches/server/0046-Purpur-use-alternative-keep-alive.patch similarity index 100% rename from patches/server/0047-Purpur-use-alternative-keep-alive.patch rename to patches/server/0046-Purpur-use-alternative-keep-alive.patch diff --git a/patches/server/0048-KioCG-Chunk-API-and-display-of-chunkhot-in-tpsbar.patch b/patches/server/0047-KioCG-Chunk-API-and-display-of-chunkhot-in-tpsbar.patch similarity index 100% rename from patches/server/0048-KioCG-Chunk-API-and-display-of-chunkhot-in-tpsbar.patch rename to patches/server/0047-KioCG-Chunk-API-and-display-of-chunkhot-in-tpsbar.patch diff --git a/patches/server/0049-Threaded-region-start-tick-and-finished-tick-event.patch b/patches/server/0048-Threaded-region-start-tick-and-finished-tick-event.patch similarity index 100% rename from patches/server/0049-Threaded-region-start-tick-and-finished-tick-event.patch rename to patches/server/0048-Threaded-region-start-tick-and-finished-tick-event.patch diff --git a/patches/server/0050-Fix-MC-2025.patch b/patches/server/0049-Fix-MC-2025.patch similarity index 100% rename from patches/server/0050-Fix-MC-2025.patch rename to patches/server/0049-Fix-MC-2025.patch diff --git a/patches/server/0051-FoliaPR-Add-TPS-From-Region.patch b/patches/server/0050-FoliaPR-Add-TPS-From-Region.patch similarity index 100% rename from patches/server/0051-FoliaPR-Add-TPS-From-Region.patch rename to patches/server/0050-FoliaPR-Add-TPS-From-Region.patch