mirror of
https://github.com/PaperMC/Paper.git
synced 2024-11-23 11:06:29 +01:00
184 lines
8.5 KiB
Diff
184 lines
8.5 KiB
Diff
From b1794a06ccd794dd501b048241fb45d7d2d5364d 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 ce43e7bb..e35e72e8 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
@@ -344,4 +344,18 @@ public class PaperWorldConfig {
|
|
private void isHopperPushBased() {
|
|
isHopperPushBased = getBoolean("hopper.push-based", false);
|
|
}
|
|
+
|
|
+ public long delayChunkUnloadsBy;
|
|
+ private void delayChunkUnloadsBy() {
|
|
+ delayChunkUnloadsBy = PaperConfig.getSeconds(getString("delay-chunk-unloads-by", "10s"));
|
|
+ if (delayChunkUnloadsBy > 0) {
|
|
+ log("Delaying chunk unloads by " + delayChunkUnloadsBy + " seconds");
|
|
+ delayChunkUnloadsBy *= 1000;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ public boolean skipEntityTickingInChunksScheduledForUnload = true;
|
|
+ private void skipEntityTickingInChunksScheduledForUnload() {
|
|
+ skipEntityTickingInChunksScheduledForUnload = getBoolean("skip-entity-ticking-in-chunks-scheduled-for-unload", skipEntityTickingInChunksScheduledForUnload);
|
|
+ }
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
|
|
index a847aa07..8ec26b97 100644
|
|
--- a/src/main/java/net/minecraft/server/Chunk.java
|
|
+++ b/src/main/java/net/minecraft/server/Chunk.java
|
|
@@ -30,6 +30,7 @@ public class Chunk {
|
|
private boolean j;
|
|
public final World world;
|
|
public final int[] heightMap;
|
|
+ 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 5cc192bb..47159bff 100644
|
|
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
@@ -315,6 +315,19 @@ public class ChunkProviderServer implements IChunkProvider {
|
|
|
|
activityAccountant.endActivity(); // Spigot
|
|
}
|
|
+ // 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.b();
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
|
|
index 3d30e183..48a008e0 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 ad1d90b5..0b10f168 100644
|
|
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
@@ -487,7 +487,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/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
|
|
index bce3fca8..fccfd3dd 100644
|
|
--- a/src/main/java/net/minecraft/server/World.java
|
|
+++ b/src/main/java/net/minecraft/server/World.java
|
|
@@ -1594,7 +1594,13 @@ public abstract class World implements IBlockAccess {
|
|
if (!tileentity.y() && tileentity.u()) {
|
|
BlockPosition blockposition = tileentity.getPosition();
|
|
|
|
- if (this.isLoaded(blockposition) && this.P.a(blockposition)) {
|
|
+ // Paper start - Skip ticking in chunks scheduled for unload
|
|
+ net.minecraft.server.Chunk chunk = this.getChunkIfLoaded(blockposition);
|
|
+ boolean shouldTick = chunk != null;
|
|
+ if(this.paperConfig.skipEntityTickingInChunksScheduledForUnload)
|
|
+ shouldTick = shouldTick && !chunk.isUnloading() && chunk.scheduledForUnload == null;
|
|
+ if (shouldTick && this.P.a(blockposition)) {
|
|
+ // Paper end
|
|
try {
|
|
this.methodProfiler.a(() -> {
|
|
return String.valueOf(TileEntity.a(tileentity.getClass()));
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
index 69dc11e2..284dc639 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
@@ -1576,7 +1576,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;
|
|
}
|
|
|
|
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
|
|
index 47865c02..b79bf70f 100644
|
|
--- a/src/main/java/org/spigotmc/ActivationRange.java
|
|
+++ b/src/main/java/org/spigotmc/ActivationRange.java
|
|
@@ -283,6 +283,10 @@ public class ActivationRange
|
|
{
|
|
isActive = false;
|
|
}
|
|
+ // Paper start - Skip ticking in chunks scheduled for unload
|
|
+ if(entity.world.paperConfig.skipEntityTickingInChunksScheduledForUnload && (chunk == null || chunk.isUnloading() || chunk.scheduledForUnload != null))
|
|
+ isActive = false;
|
|
+ // Paper end
|
|
return isActive;
|
|
}
|
|
}
|
|
--
|
|
2.17.0
|
|
|