diff options
Diffstat (limited to 'patches/removed/1.19.2-legacy-chunksystem/0801-Actually-unload-POI-data.patch')
-rw-r--r-- | patches/removed/1.19.2-legacy-chunksystem/0801-Actually-unload-POI-data.patch | 321 |
1 files changed, 321 insertions, 0 deletions
diff --git a/patches/removed/1.19.2-legacy-chunksystem/0801-Actually-unload-POI-data.patch b/patches/removed/1.19.2-legacy-chunksystem/0801-Actually-unload-POI-data.patch new file mode 100644 index 0000000000..bf5d29c068 --- /dev/null +++ b/patches/removed/1.19.2-legacy-chunksystem/0801-Actually-unload-POI-data.patch @@ -0,0 +1,321 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf <[email protected]> +Date: Mon, 31 Aug 2020 11:08:17 -0700 +Subject: [PATCH] Actually unload POI data + +While it's not likely for a poi data leak to be meaningful, +sometimes it is. + +This patch also prevents the saving/unloading of POI data when +world saving is disabled. + +diff --git a/src/main/java/net/minecraft/server/ChunkSystem.java b/src/main/java/net/minecraft/server/ChunkSystem.java +index 2a099fe0d514f181bf2b452d5333bc29b0d29e43..81ea64443a843736f9ada97900d173c302e39ba0 100644 +--- a/src/main/java/net/minecraft/server/ChunkSystem.java ++++ b/src/main/java/net/minecraft/server/ChunkSystem.java +@@ -270,6 +270,7 @@ public final class ChunkSystem { + for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { + chunkMap.regionManagers.get(index).addChunk(holder.pos.x, holder.pos.z); + } ++ chunkMap.getPoiManager().dequeueUnload(holder.pos.longKey); // Paper - unload POI data + } + + public static void onChunkHolderDelete(final ServerLevel level, final ChunkHolder holder) { +@@ -277,6 +278,7 @@ public final class ChunkSystem { + for (int index = 0, len = chunkMap.regionManagers.size(); index < len; ++index) { + chunkMap.regionManagers.get(index).removeChunk(holder.pos.x, holder.pos.z); + } ++ chunkMap.getPoiManager().queueUnload(holder.pos.longKey, MinecraftServer.currentTickLong + 1); // Paper - unload POI data + } + + public static void onChunkBorder(LevelChunk chunk, ChunkHolder holder) { +diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java +index fe10c770b511fa8a38ece2bf9679492a85b28eff..a5e74d30045a171f5ed66a115fbd429e9ab412af 100644 +--- a/src/main/java/net/minecraft/server/level/ChunkMap.java ++++ b/src/main/java/net/minecraft/server/level/ChunkMap.java +@@ -1016,7 +1016,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + + private void processUnloads(BooleanSupplier shouldKeepTicking) { + LongIterator longiterator = this.toDrop.iterator(); +- for (int i = 0; longiterator.hasNext() && (shouldKeepTicking.getAsBoolean() || i < 200 || this.toDrop.size() > 2000); longiterator.remove()) { ++ for (int i = 0; longiterator.hasNext() && (shouldKeepTicking.getAsBoolean() || i < 200 || this.toDrop.size() > 2000); longiterator.remove()) { // Paper - diff on change + long j = longiterator.nextLong(); + ChunkHolder playerchunk = this.updatingChunks.queueRemove(j); // Paper - Don't copy + +@@ -1164,6 +1164,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider + } + this.poiManager.loadInData(pos, chunkHolder.poiData); + chunkHolder.tasks.forEach(Runnable::run); ++ this.getPoiManager().dequeueUnload(pos.longKey); // Paper + + if (chunkHolder.protoChunk != null) { + ProtoChunk protochunk = chunkHolder.protoChunk; +diff --git a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java +index 497a81e49d54380713c18523ae8f09f94c453721..210b0cdd4831421c8f43c3d823ac8e962b56bbbc 100644 +--- a/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java ++++ b/src/main/java/net/minecraft/world/entity/ai/village/poi/PoiManager.java +@@ -1,5 +1,6 @@ + package net.minecraft.world.entity.ai.village.poi; + ++import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; // Paper + import com.mojang.datafixers.DataFixer; + import com.mojang.datafixers.util.Pair; + import it.unimi.dsi.fastutil.longs.Long2ByteMap; +@@ -38,16 +39,145 @@ import net.minecraft.world.level.chunk.storage.SectionStorage; + public class PoiManager extends SectionStorage<PoiSection> { + public static final int MAX_VILLAGE_DISTANCE = 6; + public static final int VILLAGE_SECTION_SIZE = 1; +- private final PoiManager.DistanceTracker distanceTracker; ++ // Paper start - unload poi data ++ // the vanilla tracker needs to be replaced because it does not support level removes ++ private final io.papermc.paper.util.misc.Delayed26WayDistancePropagator3D villageDistanceTracker = new io.papermc.paper.util.misc.Delayed26WayDistancePropagator3D(); ++ static final int POI_DATA_SOURCE = 7; ++ public static int convertBetweenLevels(final int level) { ++ return POI_DATA_SOURCE - level; ++ } ++ ++ protected void updateDistanceTracking(long section) { ++ if (this.isVillageCenter(section)) { ++ this.villageDistanceTracker.setSource(section, POI_DATA_SOURCE); ++ } else { ++ this.villageDistanceTracker.removeSource(section); ++ } ++ } ++ // Paper end - unload poi data + private final LongSet loadedChunks = new LongOpenHashSet(); + public final net.minecraft.server.level.ServerLevel world; // Paper // Paper public + + public PoiManager(Path path, DataFixer dataFixer, boolean dsync, RegistryAccess registryManager, LevelHeightAccessor world) { + super(path, PoiSection::codec, PoiSection::new, dataFixer, DataFixTypes.POI_CHUNK, dsync, registryManager, world); ++ if (world == null) { throw new IllegalStateException("world must be non-null"); } // Paper - require non-null + this.world = (net.minecraft.server.level.ServerLevel)world; // Paper +- this.distanceTracker = new PoiManager.DistanceTracker(); + } + ++ // Paper start - actually unload POI data ++ private final java.util.TreeSet<QueuedUnload> queuedUnloads = new java.util.TreeSet<>(); ++ private final Long2ObjectOpenHashMap<QueuedUnload> queuedUnloadsByCoordinate = new Long2ObjectOpenHashMap<>(); ++ ++ static final class QueuedUnload implements Comparable<QueuedUnload> { ++ ++ private final long unloadTick; ++ private final long coordinate; ++ ++ public QueuedUnload(long unloadTick, long coordinate) { ++ this.unloadTick = unloadTick; ++ this.coordinate = coordinate; ++ } ++ ++ @Override ++ public int compareTo(QueuedUnload other) { ++ if (other.unloadTick == this.unloadTick) { ++ return Long.compare(this.coordinate, other.coordinate); ++ } else { ++ return Long.compare(this.unloadTick, other.unloadTick); ++ } ++ } ++ ++ @Override ++ public int hashCode() { ++ int hash = 1; ++ hash = hash * 31 + Long.hashCode(this.unloadTick); ++ hash = hash * 31 + Long.hashCode(this.coordinate); ++ return hash; ++ } ++ ++ @Override ++ public boolean equals(Object obj) { ++ if (obj == null || obj.getClass() != QueuedUnload.class) { ++ return false; ++ } ++ QueuedUnload other = (QueuedUnload)obj; ++ return other.unloadTick == this.unloadTick && other.coordinate == this.coordinate; ++ } ++ } ++ ++ long determineDelay(long coordinate) { ++ if (this.isEmpty(coordinate)) { ++ return 5 * 60 * 20; ++ } else { ++ return 60 * 20; ++ } ++ } ++ ++ public void queueUnload(long coordinate, long minTarget) { ++ io.papermc.paper.util.TickThread.softEnsureTickThread("async poi unload queue"); ++ QueuedUnload unload = new QueuedUnload(minTarget + this.determineDelay(coordinate), coordinate); ++ QueuedUnload existing = this.queuedUnloadsByCoordinate.put(coordinate, unload); ++ if (existing != null) { ++ this.queuedUnloads.remove(existing); ++ } ++ this.queuedUnloads.add(unload); ++ } ++ ++ public void dequeueUnload(long coordinate) { ++ io.papermc.paper.util.TickThread.softEnsureTickThread("async poi unload dequeue"); ++ QueuedUnload unload = this.queuedUnloadsByCoordinate.remove(coordinate); ++ if (unload != null) { ++ this.queuedUnloads.remove(unload); ++ } ++ } ++ ++ public void pollUnloads(BooleanSupplier canSleepForTick) { ++ io.papermc.paper.util.TickThread.softEnsureTickThread("async poi unload"); ++ long currentTick = net.minecraft.server.MinecraftServer.currentTickLong; ++ net.minecraft.server.level.ServerChunkCache chunkProvider = this.world.getChunkSource(); ++ net.minecraft.server.level.ChunkMap playerChunkMap = chunkProvider.chunkMap; ++ // copied target determination from PlayerChunkMap ++ ++ java.util.Iterator<QueuedUnload> iterator = this.queuedUnloads.iterator(); ++ for (int i = 0; iterator.hasNext() && (i < 200 || this.queuedUnloads.size() > 2000 || canSleepForTick.getAsBoolean()); i++) { ++ QueuedUnload unload = iterator.next(); ++ if (unload.unloadTick > currentTick) { ++ break; ++ } ++ ++ long coordinate = unload.coordinate; ++ ++ iterator.remove(); ++ this.queuedUnloadsByCoordinate.remove(coordinate); ++ ++ if (playerChunkMap.getUnloadingChunkHolder(net.minecraft.server.MCUtil.getCoordinateX(coordinate), net.minecraft.server.MCUtil.getCoordinateZ(coordinate)) != null ++ || playerChunkMap.getUpdatingChunkIfPresent(coordinate) != null) { ++ continue; ++ } ++ ++ this.unloadData(coordinate); ++ } ++ } ++ ++ @Override ++ public void unloadData(long coordinate) { ++ io.papermc.paper.util.TickThread.softEnsureTickThread("async unloading poi data"); ++ super.unloadData(coordinate); ++ } ++ ++ @Override ++ protected void onUnload(long coordinate) { ++ io.papermc.paper.util.TickThread.softEnsureTickThread("async poi unload callback"); ++ this.loadedChunks.remove(coordinate); ++ int chunkX = net.minecraft.server.MCUtil.getCoordinateX(coordinate); ++ int chunkZ = net.minecraft.server.MCUtil.getCoordinateZ(coordinate); ++ for (int section = this.levelHeightAccessor.getMinSection(); section < this.levelHeightAccessor.getMaxSection(); ++section) { ++ long sectionPos = SectionPos.asLong(chunkX, section, chunkZ); ++ this.updateDistanceTracking(sectionPos); ++ } ++ } ++ // Paper end - actually unload POI data ++ + public void add(BlockPos pos, Holder<PoiType> type) { + this.getOrCreate(SectionPos.asLong(pos)).add(pos, type); + } +@@ -201,8 +331,8 @@ public class PoiManager extends SectionStorage<PoiSection> { + } + + public int sectionsToVillage(SectionPos pos) { +- this.distanceTracker.runAllUpdates(); +- return this.distanceTracker.getLevel(pos.asLong()); ++ this.villageDistanceTracker.propagateUpdates(); // Paper - replace distance tracking util ++ return convertBetweenLevels(this.villageDistanceTracker.getLevel(io.papermc.paper.util.CoordinateUtils.getChunkSectionKey(pos))); // Paper - replace distance tracking util + } + + boolean isVillageCenter(long pos) { +@@ -217,7 +347,7 @@ public class PoiManager extends SectionStorage<PoiSection> { + @Override + public void tick(BooleanSupplier shouldKeepTicking) { + // Paper start - async chunk io +- while (!this.dirty.isEmpty() && shouldKeepTicking.getAsBoolean()) { ++ while (!this.dirty.isEmpty() && shouldKeepTicking.getAsBoolean() && !this.world.noSave()) { // Paper - unload POI data - don't write to disk if saving is disabled + ChunkPos chunkcoordintpair = SectionPos.of(this.dirty.firstLong()).chunk(); + + net.minecraft.nbt.CompoundTag data; +@@ -227,19 +357,24 @@ public class PoiManager extends SectionStorage<PoiSection> { + com.destroystokyo.paper.io.PaperFileIOThread.Holder.INSTANCE.scheduleSave(this.world, + chunkcoordintpair.x, chunkcoordintpair.z, data, null, com.destroystokyo.paper.io.PrioritizedTaskQueue.NORMAL_PRIORITY); + } ++ // Paper start - unload POI data ++ if (!this.world.noSave()) { // don't write to disk if saving is disabled ++ this.pollUnloads(shouldKeepTicking); ++ } ++ // Paper end - unload POI data + // Paper end +- this.distanceTracker.runAllUpdates(); ++ this.villageDistanceTracker.propagateUpdates(); // Paper - replace distance tracking until + } + + @Override + protected void setDirty(long pos) { + super.setDirty(pos); +- this.distanceTracker.update(pos, this.distanceTracker.getLevelFromSource(pos), false); ++ this.updateDistanceTracking(pos); // Paper - move to new distance tracking util + } + + @Override + protected void onSectionLoad(long pos) { +- this.distanceTracker.update(pos, this.distanceTracker.getLevelFromSource(pos), false); ++ this.updateDistanceTracking(pos); // Paper - move to new distance tracking util + } + + public void checkConsistencyWithBlocks(ChunkPos chunkPos, LevelChunkSection chunkSection) { +@@ -297,7 +432,7 @@ public class PoiManager extends SectionStorage<PoiSection> { + + @Override + protected int getLevelFromSource(long id) { +- return PoiManager.this.isVillageCenter(id) ? 0 : 7; ++ return PoiManager.this.isVillageCenter(id) ? 0 : 7; // Paper - unload poi data - diff on change, this specifies the source level to use for distance tracking + } + + @Override +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java +index 10e8d1e36639cca21aa451e81cdab90ba9e9a496..954819db8ada38ef2c832151be8a96492e76390a 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/SectionStorage.java +@@ -58,6 +58,40 @@ public class SectionStorage<R> extends RegionFileStorage implements AutoCloseabl + // Paper - remove mojang I/O thread + } + ++ // Paper start - actually unload POI data ++ public void unloadData(long coordinate) { ++ ChunkPos chunkPos = new ChunkPos(coordinate); ++ this.flush(chunkPos); ++ ++ Long2ObjectMap<Optional<R>> data = this.storage; ++ int before = data.size(); ++ ++ for (int section = this.levelHeightAccessor.getMinSection(); section < this.levelHeightAccessor.getMaxSection(); ++section) { ++ data.remove(SectionPos.asLong(chunkPos.x, section, chunkPos.z)); ++ } ++ ++ if (before != data.size()) { ++ this.onUnload(coordinate); ++ } ++ } ++ ++ protected void onUnload(long coordinate) {} ++ ++ public boolean isEmpty(long coordinate) { ++ Long2ObjectMap<Optional<R>> data = this.storage; ++ int x = net.minecraft.server.MCUtil.getCoordinateX(coordinate); ++ int z = net.minecraft.server.MCUtil.getCoordinateZ(coordinate); ++ for (int section = this.levelHeightAccessor.getMinSection(); section < this.levelHeightAccessor.getMaxSection(); ++section) { ++ Optional<R> optional = data.get(SectionPos.asLong(x, section, z)); ++ if (optional != null && optional.orElse(null) != null) { ++ return false; ++ } ++ } ++ ++ return true; ++ } ++ // Paper end - actually unload POI data ++ + protected void tick(BooleanSupplier shouldKeepTicking) { + while(this.hasWork() && shouldKeepTicking.getAsBoolean()) { + ChunkPos chunkPos = SectionPos.of(this.dirty.firstLong()).chunk(); +@@ -175,6 +209,7 @@ public class SectionStorage<R> extends RegionFileStorage implements AutoCloseabl + }); + } + } ++ if (this instanceof net.minecraft.world.entity.ai.village.poi.PoiManager) { ((net.minecraft.world.entity.ai.village.poi.PoiManager)this).queueUnload(pos.longKey, net.minecraft.server.MinecraftServer.currentTickLong + 1); } // Paper - unload POI data + + } + |