From 112881002917ae4b3ca9a6678c1b9fee3e66f4db Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Mon, 15 May 2023 20:37:29 -0700 Subject: [PATCH] Always recalculate light list on protochunk deserialize I noticed during my stress testing that the total size of the light list was far too large, which indicates many duplicates. For me, this caused many GC problems which made stress testing harder. It turns out, it was possible for the light list recalculation logic to occur _and_ the addition of the light list data from the NBT data. Since there is no logic to de-duplicate this list, every chunk load would re-add all light sources into the light list and the light list would grow uncontrollably. Since the recalculation logic would often run, I have decided to solve this by discarding the data on disk and always just calculating the list from the chunk data alone. Additionally, I have applied an optimization from Vanilla 1.20 to avoid searching sections without light sources by first checking the palette for possible block sources. Now my stress tests do not have issues with GC at all. --- ...te-light-list-on-protochunk-deserial.patch | 68 +++++++++++++++++++ 1 file changed, 68 insertions(+) create mode 100644 patches/server/0031-Always-recalculate-light-list-on-protochunk-deserial.patch diff --git a/patches/server/0031-Always-recalculate-light-list-on-protochunk-deserial.patch b/patches/server/0031-Always-recalculate-light-list-on-protochunk-deserial.patch new file mode 100644 index 0000000..c1fe2bc --- /dev/null +++ b/patches/server/0031-Always-recalculate-light-list-on-protochunk-deserial.patch @@ -0,0 +1,68 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Mon, 15 May 2023 20:31:36 -0700 +Subject: [PATCH] Always recalculate light list on protochunk deserialize + +I noticed during my stress testing that the total size of the +light list was far too large, which indicates many duplicates. +For me, this caused many GC problems which made stress testing +harder. + +It turns out, it was possible for the light list recalculation +logic to occur _and_ the addition of the light list data from +the NBT data. Since there is no logic to de-duplicate this list, +every chunk load would re-add all light sources into the light +list and the light list would grow uncontrollably. + +Since the recalculation logic would often run, I have +decided to solve this by discarding the data on disk and always +just calculating the list from the chunk data alone. Additionally, +I have applied an optimization from Vanilla 1.20 to avoid +searching sections without light sources by first checking the +palette for possible block sources. + +Now my stress tests do not have issues with GC at all. + +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 3c9ae42290c2e0cb70bb08e97f3ea2c3fb594c7d..200915f5accdb26c634cc77300a7d3275a8b1e0a 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 +@@ -321,7 +321,7 @@ public class ChunkSerializer { + BelowZeroRetrogen belowzeroretrogen = protochunk.getBelowZeroRetrogen(); + boolean flag5 = chunkstatus.isOrAfter(ChunkStatus.LIGHT) || belowzeroretrogen != null && belowzeroretrogen.targetStatus().isOrAfter(ChunkStatus.LIGHT); + +- if (!flag) { // Paper - fix incorrect parsing of blocks that emit light - it should always parse it, unless the chunk is marked as lit ++ if (true) { // Paper - fix incorrect parsing of blocks that emit light - it should always parse it, unless the chunk is marked as lit // Folia - always recalculate light data to eliminate duplicates + // Paper start - let's make sure the implementation isn't as slow as possible + int offX = chunkPos.x << 4; + int offZ = chunkPos.z << 4; +@@ -332,7 +332,7 @@ public class ChunkSerializer { + LevelChunkSection[] sections = achunksection; + for (int sectionY = minChunkSection; sectionY <= maxChunkSection; ++sectionY) { + LevelChunkSection section = sections[sectionY - minChunkSection]; +- if (section == null || section.hasOnlyAir()) { ++ if (section == null || section.hasOnlyAir() || !section.maybeHas((BlockState state) -> state.getLightEmission() > 0)) { // Folia - always recalculate light data to eliminate duplicates - skip sections that definitely have no sources + // no sources in empty sections + continue; + } +@@ -416,19 +416,7 @@ public class ChunkSerializer { + ((ChunkAccess) object1).setBlockEntityNbt(nbttagcompound4); + } + +- ListTag nbttaglist4 = nbt.getList("Lights", 9); +- +- for (int l1 = 0; l1 < nbttaglist4.size(); ++l1) { +- LevelChunkSection chunksection1 = achunksection[l1]; +- +- if (chunksection1 != null && !chunksection1.hasOnlyAir()) { +- ListTag nbttaglist5 = nbttaglist4.getList(l1); +- +- for (int i2 = 0; i2 < nbttaglist5.size(); ++i2) { +- protochunk1.addLight(nbttaglist5.getShort(i2), l1); +- } +- } +- } ++ // Folia - always recalculate light data to eliminate duplicates + + nbttagcompound4 = nbt.getCompound("CarvingMasks"); + Iterator iterator2 = nbttagcompound4.getAllKeys().iterator();