diff --git a/patches/server/0836-Cache-palette-array.patch b/patches/server/0836-Cache-palette-array.patch new file mode 100644 index 0000000000..2c787bbbc6 --- /dev/null +++ b/patches/server/0836-Cache-palette-array.patch @@ -0,0 +1,61 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Paul Sauve +Date: Thu, 4 Feb 2021 23:28:46 -0600 +Subject: [PATCH] Cache palette array + +Instead of allocating the 4KB for every chunk section, cache it locally and +reuse it for other chunk sections to save on allocations. These allocations add +up very quickly when saving chunks frequently. + +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 c9e942669458668a184aaec3bc0a5509dd6ab5f0..ac84d49d7819666a89cacbe9ef1199cf22ac2ac3 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java ++++ b/src/main/java/net/minecraft/world/level/chunk/PalettedContainer.java +@@ -263,13 +263,17 @@ public class PalettedContainer implements PaletteResize { + + } + ++ // Paper start - allow reusing int array + public synchronized void write(CompoundTag nbt, String paletteKey, String dataKey) { // Paper - synchronize ++ this.write(nbt, paletteKey, dataKey, new int[4096]); ++ } ++ public synchronized void write(CompoundTag nbt, String paletteKey, String dataKey, int[] is) { // Paper - synchronize // Paper end + try { + this.acquire(); + HashMapPalette hashMapPalette = new HashMapPalette<>(this.registry, this.bits, this.dummyPaletteResize, this.reader, this.writer); + T object = this.defaultValue; + int i = hashMapPalette.idFor(this.defaultValue); +- int[] is = new int[4096]; ++ //int[] is = new int[4096]; // Paper - will now be pulled from ThreadLocal + + for(int j = 0; j < 4096; ++j) { + T object2 = this.get(j); +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +index 7921ee2786d0d6a60d43786b20efc03a0f9178e3..10f15b8c7763a980aec47a4b4dda5686e60642ce 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/ChunkSerializer.java +@@ -500,6 +500,7 @@ public class ChunkSerializer { + return new AsyncSaveData(blockLight, skyLight, blockTickListSerialized, fluidTickListSerialized, blockEntitiesSerialized, world.getGameTime()); + } + ++ private static final ThreadLocal PALETTE_ARRAY = ThreadLocal.withInitial(() -> new int[4096]); // Paper - maintain a per-thread cache for saving palettes + public static CompoundTag write(ServerLevel world, ChunkAccess chunk) { + return saveChunk(world, chunk, null); + } +@@ -533,6 +534,7 @@ public class ChunkSerializer { + ThreadedLevelLightEngine lightenginethreaded = world.getChunkSource().getLightEngine(); + boolean flag = chunk.isLightCorrect(); + ++ int[] is = PALETTE_ARRAY.get(); // Paper - use cached + for (int i = lightenginethreaded.getMinLightSection(); i < lightenginethreaded.getMaxLightSection(); ++i) { + int finalI = i; // CraftBukkit - decompile errors + LevelChunkSection chunksection = (LevelChunkSection) Arrays.stream(achunksection).filter((chunksection1) -> { +@@ -547,7 +549,7 @@ public class ChunkSerializer { + + nbttagcompound2.putByte("Y", (byte) (i & 255)); + if (chunksection != LevelChunk.EMPTY_SECTION) { +- chunksection.getStates().write(nbttagcompound2, "Palette", "BlockStates"); ++ chunksection.getStates().write(nbttagcompound2, "Palette", "BlockStates", is); // Paper - reuse array + } + + // Paper start - replace light engine