diff --git a/Spigot-Server-Patches/0166-Delay-Chunk-Unloads-based-on-Player-Movement.patch b/Spigot-Server-Patches/0166-Delay-Chunk-Unloads-based-on-Player-Movement.patch new file mode 100644 index 000000000..504b11492 --- /dev/null +++ b/Spigot-Server-Patches/0166-Delay-Chunk-Unloads-based-on-Player-Movement.patch @@ -0,0 +1,146 @@ +From 68e4453fda0928d5f744d39a343cd16afc82bed2 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 18 Jun 2016 23:22:12 -0400 +Subject: [PATCH] Delay Chunk Unloads based on Player Movement + +When players are moving in the world, doing things such as building or exploring, +they will commonly go back and forth in a small area. This causes a ton of chunk load +and unload activity on the edge chunks of their view distance. + +A simple back and forth movement in 6 blocks could spam a chunk to thrash a +loading and unload cycle over and over again. + +This is very wasteful. This system introduces a delay of inactivity on a chunk +before it actually unloads, which is maintained separately from ChunkGC. + +This allows servers with smaller worlds who do less long distance exploring to stop +wasting cpu cycles on saving/unloading/reloading chunks repeatedly. + +diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +index 0d2af96..bc41b7e 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +@@ -364,6 +364,15 @@ public class PaperWorldConfig { + } + } + ++ public long delayChunkUnloadsBy; ++ private void delayChunkUnloadsBy() { ++ delayChunkUnloadsBy = PaperConfig.getSeconds(getString("delay-chunk-unloads-by", "30s")); ++ if (delayChunkUnloadsBy > 0) { ++ log("Delaying chunk unloads by " + delayChunkUnloadsBy + " seconds"); ++ delayChunkUnloadsBy *= 1000; ++ } ++ } ++ + public boolean isHopperPushBased; + private void isHopperPushBased() { + isHopperPushBased = getBoolean("hopper.push-based", true); +diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java +index 2429579..e4be7d8 100644 +--- a/src/main/java/net/minecraft/server/Chunk.java ++++ b/src/main/java/net/minecraft/server/Chunk.java +@@ -31,6 +31,7 @@ public class Chunk { + public final World world; + public final int[] heightMap; + public final long chunkKey; // Paper ++ public Long scheduledForUnload; // Paper - delay chunk unloads + public final int locX; + public final int locZ; + private boolean m; +diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java +index 33b3db7..21ca3c5 100644 +--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java ++++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java +@@ -351,6 +351,19 @@ public class ChunkProviderServer implements IChunkProvider { + } + } + } ++ // Paper start - delayed chunk unloads ++ long now = System.currentTimeMillis(); ++ long unloadAfter = world.paperConfig.delayChunkUnloadsBy; ++ if (unloadAfter > 0) { ++ //noinspection Convert2streamapi ++ for (Chunk chunk : chunks.values()) { ++ if (chunk.scheduledForUnload != null && now - chunk.scheduledForUnload > unloadAfter) { ++ chunk.scheduledForUnload = null; ++ unload(chunk); ++ } ++ } ++ } ++ // Paper end + + this.chunkLoader.a(); + } +diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java +index dd40e98..f109e98 100644 +--- a/src/main/java/net/minecraft/server/PlayerChunk.java ++++ b/src/main/java/net/minecraft/server/PlayerChunk.java +@@ -32,8 +32,16 @@ public class PlayerChunk { + public void run() { + loadInProgress = false; + PlayerChunk.this.chunk = PlayerChunk.this.playerChunkMap.getWorld().getChunkProviderServer().getOrLoadChunkAt(location.x, location.z); ++ markChunkUsed(); // Paper - delay chunk unloads + } + }; ++ // Paper start - delay chunk unloads ++ public final void markChunkUsed() { ++ if (chunk != null && chunk.scheduledForUnload != null) { ++ chunk.scheduledForUnload = null; ++ } ++ } ++ // Paper end + // CraftBukkit end + + public PlayerChunk(PlayerChunkMap playerchunkmap, int i, int j) { +@@ -42,6 +50,7 @@ public class PlayerChunk { + // CraftBukkit start + loadInProgress = true; + this.chunk = playerchunkmap.getWorld().getChunkProviderServer().getChunkAt(i, j, loadedRunnable, false); ++ markChunkUsed(); // Paper - delay chunk unloads + // CraftBukkit end + } + +@@ -110,6 +119,7 @@ public class PlayerChunk { + if (!loadInProgress) { + loadInProgress = true; + this.chunk = playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(this.location.x, this.location.z, loadedRunnable, flag); ++ markChunkUsed(); // Paper - delay chunk unloads + } + // CraftBukkit end + +diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java +index 6320247..9fed846 100644 +--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java ++++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java +@@ -458,7 +458,13 @@ public class PlayerChunkMap { + Chunk chunk = playerchunk.f(); + + if (chunk != null) { +- this.getWorld().getChunkProviderServer().unload(chunk); ++ // Paper start - delay chunk unloads ++ if (world.paperConfig.delayChunkUnloadsBy <= 0) { ++ this.getWorld().getChunkProviderServer().unload(chunk); ++ } else { ++ chunk.scheduledForUnload = System.currentTimeMillis(); ++ } ++ // Paper end + } + + } +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 22d142a..8aaf64f 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -1548,7 +1548,7 @@ public class CraftWorld implements World { + ChunkProviderServer cps = world.getChunkProviderServer(); + for (net.minecraft.server.Chunk chunk : cps.chunks.values()) { + // If in use, skip it +- if (isChunkInUse(chunk.locX, chunk.locZ)) { ++ if (isChunkInUse(chunk.locX, chunk.locZ) || chunk.scheduledForUnload != null) { // Paper - delayed chunk unloads + continue; + } + +-- +2.9.0 +