mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-19 14:59:25 +00:00
Upstream has released updates that appear to apply and compile correctly Purpur Changes: PurpurMC/Purpur@efc76215 Add missing copper blocks to waxables and weatherables options (#1712) PurpurMC/Purpur@3ca0d663 Updated Upstream (Paper) PurpurMC/Purpur@917675d0 Updated Upstream (Paper) PurpurMC/Purpur@ffe2f809 Add option to disable Warden Sonic Boom (#1713)
218 lines
11 KiB
Diff
218 lines
11 KiB
Diff
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com>
|
|
Date: Sun, 6 Jul 2025 02:23:03 +0300
|
|
Subject: [PATCH] lithium: faster chunk serialization
|
|
|
|
This patch is based on the following mixins and classes:
|
|
* "net/caffeinemc/mods/lithium/common/world/chunk/CompactingPackedIntegerArray.java"
|
|
* "net/caffeinemc/mods/lithium/common/world/chunk/LithiumHashPalette.java"
|
|
* "net/caffeinemc/mods/lithium/mixin/chunk/serialization/SimpleBitStorageMixin.java"
|
|
* "net/caffeinemc/mods/lithium/mixin/chunk/serialization/PalettedContainerMixin.java"
|
|
By: Angeline <jellysquid3@users.noreply.github.com>
|
|
As part of: Lithium (https://github.com/CaffeineMC/lithium)
|
|
Licensed under: LGPL-3.0 (https://www.gnu.org/licenses/lgpl-3.0.html)
|
|
|
|
diff --git a/net/minecraft/util/BitStorage.java b/net/minecraft/util/BitStorage.java
|
|
index 02502d50f0255f5bbcc0ecb965abb48cc1a112da..89c65b8e4b99b78ec847f0ef958166a645ed4324 100644
|
|
--- a/net/minecraft/util/BitStorage.java
|
|
+++ b/net/minecraft/util/BitStorage.java
|
|
@@ -38,4 +38,6 @@ public interface BitStorage extends ca.spottedleaf.moonrise.patches.block_counti
|
|
return ret;
|
|
}
|
|
// Paper end - block counting
|
|
+
|
|
+ <T> void compact(net.minecraft.world.level.chunk.Palette<T> srcPalette, net.minecraft.world.level.chunk.Palette<T> dstPalette, short[] out, net.minecraft.world.level.chunk.PalettedContainer<T> resizeHandler); // DivineMC - lithium: faster chunk serialization
|
|
}
|
|
diff --git a/net/minecraft/util/SimpleBitStorage.java b/net/minecraft/util/SimpleBitStorage.java
|
|
index e6306a68c8652d4c5d22d5ecb1416f5f931f76ee..536cf90d2c4bccabe67bffde6bc4fa644a9e7d63 100644
|
|
--- a/net/minecraft/util/SimpleBitStorage.java
|
|
+++ b/net/minecraft/util/SimpleBitStorage.java
|
|
@@ -465,4 +465,44 @@ public class SimpleBitStorage implements BitStorage {
|
|
super(message);
|
|
}
|
|
}
|
|
+
|
|
+ // DivineMC start - lithium: faster chunk serialization
|
|
+ @Override
|
|
+ public <T> void compact(net.minecraft.world.level.chunk.Palette<T> srcPalette, net.minecraft.world.level.chunk.Palette<T> dstPalette, short[] out, net.minecraft.world.level.chunk.PalettedContainer<T> resizeHandler) {
|
|
+ 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), resizeHandler) + 1;
|
|
+ mappings[value] = (short) remappedId;
|
|
+ }
|
|
+
|
|
+ out[idx] = (short) (remappedId - 1);
|
|
+ bits >>= this.bits;
|
|
+
|
|
+ ++idx;
|
|
+
|
|
+ if (idx >= this.size) {
|
|
+ return;
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+ // DivineMC end - lithium: faster chunk serialization
|
|
}
|
|
diff --git a/net/minecraft/util/ZeroBitStorage.java b/net/minecraft/util/ZeroBitStorage.java
|
|
index 09fd99c9cbd23b5f3c899bfb00c9b89651948ed8..6fdd51c767399bce29dce1ecea2e13072a6f4d00 100644
|
|
--- a/net/minecraft/util/ZeroBitStorage.java
|
|
+++ b/net/minecraft/util/ZeroBitStorage.java
|
|
@@ -80,4 +80,6 @@ public class ZeroBitStorage implements BitStorage {
|
|
return ret;
|
|
}
|
|
// Paper end - block counting
|
|
+
|
|
+ @Override public <T> void compact(net.minecraft.world.level.chunk.Palette<T> srcPalette, net.minecraft.world.level.chunk.Palette<T> dstPalette, short[] out, net.minecraft.world.level.chunk.PalettedContainer<T> resizeHandler) { } // DivineMC - lithium: faster chunk serialization
|
|
}
|
|
diff --git a/net/minecraft/world/level/chunk/PalettedContainer.java b/net/minecraft/world/level/chunk/PalettedContainer.java
|
|
index 54d71bd666a946bdf6eece520e080c3f96003452..51ece91c956fd4d55eaef34a534fdb38c6d24446 100644
|
|
--- a/net/minecraft/world/level/chunk/PalettedContainer.java
|
|
+++ b/net/minecraft/world/level/chunk/PalettedContainer.java
|
|
@@ -29,6 +29,23 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
|
private final T @org.jetbrains.annotations.Nullable [] presetValues; // Paper - Anti-Xray - Add preset values
|
|
//private final ThreadingDetector threadingDetector = new ThreadingDetector("PalettedContainer"); // Paper - unused
|
|
|
|
+ // DivineMC start - lithium: faster chunk serialization
|
|
+ private static final ThreadLocal<short[]> CACHED_ARRAY_4096 = ThreadLocal.withInitial(() -> new short[4096]);
|
|
+ private static final ThreadLocal<short[]> CACHED_ARRAY_64 = ThreadLocal.withInitial(() -> new short[64]);
|
|
+
|
|
+ private Optional<LongStream> 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];
|
|
+ };
|
|
+ }
|
|
+ // DivineMC end - lithium: faster chunk serialization
|
|
+
|
|
public void acquire() {
|
|
// this.threadingDetector.checkAndLock(); // Paper - disable this - use proper synchronization
|
|
}
|
|
@@ -338,29 +355,49 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
|
public synchronized PalettedContainerRO.PackedData<T> pack(Strategy<T> strategy) { // Paper - synchronize
|
|
this.acquire();
|
|
|
|
- PalettedContainerRO.PackedData var14;
|
|
+ // DivineMC start - lithium: faster chunk serialization
|
|
+ Optional<LongStream> data = Optional.empty();
|
|
+ List<T> elements = null;
|
|
try {
|
|
- BitStorage bitStorage = this.data.storage;
|
|
- Palette<T> palette = this.data.palette;
|
|
- HashMapPalette<T> hashMapPalette = new HashMapPalette<>(bitStorage.getBits());
|
|
- int entryCount = strategy.entryCount();
|
|
- int[] ints = reencodeContents(bitStorage, palette, hashMapPalette);
|
|
- Configuration configurationForPaletteSize = strategy.getConfigurationForPaletteSize(hashMapPalette.getSize());
|
|
- int i = configurationForPaletteSize.bitsInStorage();
|
|
- Optional<LongStream> optional;
|
|
- if (i != 0) {
|
|
- SimpleBitStorage simpleBitStorage = new SimpleBitStorage(i, entryCount, ints);
|
|
- optional = Optional.of(Arrays.stream(simpleBitStorage.getRaw()));
|
|
- } else {
|
|
- optional = Optional.empty();
|
|
+ net.caffeinemc.mods.lithium.common.world.chunk.LithiumHashPalette<T> hashPalette = null;
|
|
+
|
|
+ final Palette<T> palette = this.data.palette();
|
|
+ final BitStorage storage = this.data.storage();
|
|
+ if (storage instanceof ZeroBitStorage || palette.getSize() == 1) {
|
|
+ elements = List.of(palette.valueFor(0));
|
|
+ } else if (palette instanceof net.caffeinemc.mods.lithium.common.world.chunk.LithiumHashPalette<T> lithiumHashPalette) {
|
|
+ hashPalette = lithiumHashPalette;
|
|
}
|
|
|
|
- var14 = new PalettedContainerRO.PackedData<>(hashMapPalette.getEntries(), optional, i);
|
|
+ if (elements == null) {
|
|
+ net.caffeinemc.mods.lithium.common.world.chunk.LithiumHashPalette<T> compactedPalette = new net.caffeinemc.mods.lithium.common.world.chunk.LithiumHashPalette<>(storage.getBits());
|
|
+ short[] array = this.getOrCreate(strategy.entryCount());
|
|
+
|
|
+ storage.compact(this.data.palette(), compactedPalette, array, this);
|
|
+
|
|
+ if (hashPalette != null && hashPalette.getSize() == compactedPalette.getSize() && storage.getBits() == strategy.getConfigurationForPaletteSize(hashPalette.getSize()).bitsInStorage()) { // 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 = strategy.getConfigurationForPaletteSize(compactedPalette.getSize()).bitsInStorage();
|
|
+ if (bits != 0) {
|
|
+ SimpleBitStorage copy = new SimpleBitStorage(bits, array.length);
|
|
+ for (int i = 0; i < array.length; ++i) {
|
|
+ copy.set(i, array[i]);
|
|
+ }
|
|
+
|
|
+ data = this.asOptional(copy.getRaw());
|
|
+ }
|
|
+
|
|
+ elements = compactedPalette.getElements();
|
|
+ }
|
|
+ }
|
|
} finally {
|
|
this.release();
|
|
}
|
|
|
|
- return var14;
|
|
+ return new PalettedContainerRO.PackedData<>(elements, data);
|
|
+ // DivineMC end - lithium: faster chunk serialization
|
|
}
|
|
|
|
private static <T> int[] reencodeContents(BitStorage bitStorage, Palette<T> oldPalette, Palette<T> newPalette) {
|
|
@@ -410,13 +447,31 @@ public class PalettedContainer<T> implements PaletteResize<T>, PalettedContainer
|
|
|
|
@Override
|
|
public void count(PalettedContainer.CountConsumer<T> countConsumer) {
|
|
- if (this.data.palette.getSize() == 1) {
|
|
- countConsumer.accept(this.data.palette.valueFor(0), this.data.storage.getSize());
|
|
- } else {
|
|
- Int2IntOpenHashMap map = new Int2IntOpenHashMap();
|
|
- this.data.storage.getAll(id -> map.addTo(id, 1));
|
|
- map.int2IntEntrySet().forEach(idEntry -> countConsumer.accept(this.data.palette.valueFor(idEntry.getIntKey()), idEntry.getIntValue()));
|
|
+ // DivineMC start - lithium: faster chunk serialization
|
|
+ int len = this.data.palette().getSize();
|
|
+
|
|
+ if (len > 4096) {
|
|
+ if (this.data.palette.getSize() == 1) {
|
|
+ countConsumer.accept(this.data.palette.valueFor(0), this.data.storage.getSize());
|
|
+ } else {
|
|
+ Int2IntOpenHashMap map = new Int2IntOpenHashMap();
|
|
+ this.data.storage.getAll(id -> map.addTo(id, 1));
|
|
+ map.int2IntEntrySet().forEach(idEntry -> countConsumer.accept(this.data.palette.valueFor(idEntry.getIntKey()), idEntry.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) {
|
|
+ countConsumer.accept(obj, counts[i]);
|
|
+ }
|
|
}
|
|
+ // DivineMC end - lithium: faster chunk serialization
|
|
}
|
|
|
|
@FunctionalInterface
|