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.
This commit is contained in:
parent
4d7917a87d
commit
0aa71fbf41
1 changed files with 146 additions and 0 deletions
|
@ -0,0 +1,146 @@
|
|||
From 68e4453fda0928d5f744d39a343cd16afc82bed2 Mon Sep 17 00:00:00 2001
|
||||
From: Aikar <aikar@aikar.co>
|
||||
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
|
||||
|
Loading…
Reference in a new issue