2018-12-23 18:04:13 +01:00
|
|
|
From ec6342a78de5a84e7a81431fcdbf37db320b27c8 Mon Sep 17 00:00:00 2001
|
2016-06-19 05:33:57 +02:00
|
|
|
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.
|
|
|
|
|
2018-10-01 02:34:05 +02:00
|
|
|
This also makes the Chunk GC System useless, by auto scheduling unload as soon as
|
|
|
|
a spare chunk is added to the server thats outside of view distance.
|
|
|
|
|
2016-06-19 05:33:57 +02:00
|
|
|
diff --git a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
2018-12-13 01:40:29 +01:00
|
|
|
index 42d951554..d8f258105 100644
|
2016-06-19 05:33:57 +02:00
|
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
2018-12-13 01:40:29 +01:00
|
|
|
@@ -301,4 +301,18 @@ public class PaperWorldConfig {
|
2018-07-16 22:08:09 +02:00
|
|
|
preventTntFromMovingInWater = getBoolean("prevent-tnt-from-moving-in-water", false);
|
|
|
|
log("Prevent TNT from moving in water: " + preventTntFromMovingInWater);
|
2016-06-19 05:33:57 +02:00
|
|
|
}
|
2016-07-29 03:54:48 +02:00
|
|
|
+
|
2016-06-19 05:33:57 +02:00
|
|
|
+ public long delayChunkUnloadsBy;
|
|
|
|
+ private void delayChunkUnloadsBy() {
|
2016-07-29 03:57:36 +02:00
|
|
|
+ delayChunkUnloadsBy = PaperConfig.getSeconds(getString("delay-chunk-unloads-by", "10s"));
|
2016-06-19 05:33:57 +02:00
|
|
|
+ if (delayChunkUnloadsBy > 0) {
|
|
|
|
+ log("Delaying chunk unloads by " + delayChunkUnloadsBy + " seconds");
|
|
|
|
+ delayChunkUnloadsBy *= 1000;
|
|
|
|
+ }
|
2018-05-30 22:31:55 +02:00
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public boolean skipEntityTickingInChunksScheduledForUnload = true;
|
|
|
|
+ private void skipEntityTickingInChunksScheduledForUnload() {
|
2018-05-30 22:38:27 +02:00
|
|
|
+ skipEntityTickingInChunksScheduledForUnload = getBoolean("skip-entity-ticking-in-chunks-scheduled-for-unload", skipEntityTickingInChunksScheduledForUnload);
|
2016-06-19 05:33:57 +02:00
|
|
|
+ }
|
2016-07-29 03:54:48 +02:00
|
|
|
}
|
2016-06-19 05:33:57 +02:00
|
|
|
diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java
|
2018-12-23 18:04:13 +01:00
|
|
|
index f6bfd6ece..7380c4386 100644
|
2016-06-19 05:33:57 +02:00
|
|
|
--- a/src/main/java/net/minecraft/server/Chunk.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/Chunk.java
|
2018-12-17 06:18:06 +01:00
|
|
|
@@ -41,6 +41,7 @@ public class Chunk implements IChunkAccess {
|
2018-08-26 20:11:49 +02:00
|
|
|
private boolean i;public boolean isLoaded() { return i; } // Paper - OBFHELPER
|
2016-06-19 05:33:57 +02:00
|
|
|
public final World world;
|
2018-07-16 22:08:09 +02:00
|
|
|
public final Map<HeightMap.Type, HeightMap> heightMap;
|
2016-06-19 05:33:57 +02:00
|
|
|
+ public Long scheduledForUnload; // Paper - delay chunk unloads
|
|
|
|
public final int locX;
|
|
|
|
public final int locZ;
|
2018-10-06 06:56:20 +02:00
|
|
|
private boolean l;
|
2018-10-01 02:34:05 +02:00
|
|
|
diff --git a/src/main/java/net/minecraft/server/ChunkMap.java b/src/main/java/net/minecraft/server/ChunkMap.java
|
2018-12-17 06:18:06 +01:00
|
|
|
index 8b3738c8f..2021c0d02 100644
|
2018-10-01 02:34:05 +02:00
|
|
|
--- a/src/main/java/net/minecraft/server/ChunkMap.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/ChunkMap.java
|
|
|
|
@@ -48,6 +48,15 @@ public class ChunkMap extends Long2ObjectOpenHashMap<Chunk> {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
+ // Paper start - if this is a spare chunk (not part of any players view distance), go ahead and queue it for unload.
|
|
|
|
+ if (!((WorldServer)chunk.world).getPlayerChunkMap().isChunkInUse(chunk.locX, chunk.locZ)) {
|
|
|
|
+ if (chunk.world.paperConfig.delayChunkUnloadsBy > 0) {
|
|
|
|
+ chunk.scheduledForUnload = System.currentTimeMillis();
|
|
|
|
+ } else {
|
2018-12-17 06:18:06 +01:00
|
|
|
+ ((WorldServer) chunk.world).getChunkProvider().unload(chunk);
|
2018-10-01 02:34:05 +02:00
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // Paper end
|
|
|
|
chunk.world.timings.syncChunkLoadPostTimer.stopTiming(); // Paper
|
|
|
|
// CraftBukkit end
|
|
|
|
|
2016-06-19 05:33:57 +02:00
|
|
|
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
2018-12-08 11:09:55 +01:00
|
|
|
index 1d08ec37f..516a583a8 100644
|
2016-06-19 05:33:57 +02:00
|
|
|
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
2018-12-08 11:09:55 +01:00
|
|
|
@@ -308,6 +308,19 @@ public class ChunkProviderServer implements IChunkProvider {
|
2018-08-26 20:11:49 +02:00
|
|
|
}
|
2017-01-31 05:33:54 +01:00
|
|
|
activityAccountant.endActivity(); // Spigot
|
2016-06-19 05:33:57 +02:00
|
|
|
}
|
|
|
|
+ // 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
|
|
|
|
|
2018-08-26 20:11:49 +02:00
|
|
|
this.chunkScheduler.a(booleansupplier);
|
|
|
|
}
|
2016-06-19 05:33:57 +02:00
|
|
|
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
|
2018-12-17 06:18:06 +01:00
|
|
|
index 1d672eaa1..5497a458d 100644
|
2016-06-19 05:33:57 +02:00
|
|
|
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
|
2018-12-17 06:18:06 +01:00
|
|
|
@@ -26,8 +26,23 @@ public class PlayerChunk {
|
|
|
|
ChunkProviderServer chunkproviderserver = playerchunkmap.getWorld().getChunkProvider();
|
|
|
|
chunkproviderserver.a(ix, j);
|
|
|
|
this.chunk = chunkproviderserver.getChunkAt(ix, j, true, false);
|
|
|
|
+ markChunkUsed(); // Paper - delay chunk unloads
|
|
|
|
}
|
|
|
|
|
|
|
|
+ // Paper start
|
2018-10-01 02:34:05 +02:00
|
|
|
+ private void markChunkUsed() {
|
|
|
|
+ if (chunk == null) {
|
|
|
|
+ return;
|
|
|
|
+ }
|
2018-10-01 07:00:09 +02:00
|
|
|
+ if (chunkHasPlayers) {
|
2016-06-19 05:33:57 +02:00
|
|
|
+ chunk.scheduledForUnload = null;
|
2018-10-01 02:34:05 +02:00
|
|
|
+ } else if (chunk.scheduledForUnload == null) {
|
|
|
|
+ chunk.scheduledForUnload = System.currentTimeMillis();
|
2016-06-19 05:33:57 +02:00
|
|
|
+ }
|
|
|
|
+ }
|
2018-10-01 07:00:09 +02:00
|
|
|
+ private boolean chunkHasPlayers = false;
|
2016-06-19 05:33:57 +02:00
|
|
|
+ // Paper end
|
2018-12-17 06:18:06 +01:00
|
|
|
+
|
2018-07-16 22:08:09 +02:00
|
|
|
public ChunkCoordIntPair a() {
|
2018-12-17 06:18:06 +01:00
|
|
|
return this.location;
|
|
|
|
}
|
|
|
|
@@ -38,6 +53,8 @@ public class PlayerChunk {
|
2018-10-01 02:34:05 +02:00
|
|
|
} else {
|
2018-12-17 06:18:06 +01:00
|
|
|
if (this.players.isEmpty()) {
|
2018-10-01 02:34:05 +02:00
|
|
|
this.i = this.playerChunkMap.getWorld().getTime();
|
2018-10-01 07:00:09 +02:00
|
|
|
+ chunkHasPlayers = true; // Paper - delay chunk unloads
|
2018-10-01 02:34:05 +02:00
|
|
|
+ markChunkUsed(); // Paper - delay chunk unloads
|
|
|
|
}
|
|
|
|
|
2018-12-17 06:18:06 +01:00
|
|
|
this.players.add(entityplayer);
|
|
|
|
@@ -56,6 +73,8 @@ public class PlayerChunk {
|
2018-10-01 02:34:05 +02:00
|
|
|
|
2018-12-17 06:18:06 +01:00
|
|
|
this.players.remove(entityplayer);
|
|
|
|
if (this.players.isEmpty()) {
|
2018-10-01 07:00:09 +02:00
|
|
|
+ chunkHasPlayers = false; // Paper - delay chunk unloads
|
2018-10-01 02:34:05 +02:00
|
|
|
+ markChunkUsed(); // Paper - delay chunk unloads
|
|
|
|
this.playerChunkMap.b(this);
|
|
|
|
}
|
|
|
|
|
2018-12-17 06:18:06 +01:00
|
|
|
@@ -67,6 +86,7 @@ public class PlayerChunk {
|
2018-08-26 20:11:49 +02:00
|
|
|
return true;
|
|
|
|
} else {
|
2018-12-17 06:18:06 +01:00
|
|
|
this.chunk = this.playerChunkMap.getWorld().getChunkProvider().getChunkAt(this.location.x, this.location.z, true, flag);
|
2018-08-26 20:11:49 +02:00
|
|
|
+ markChunkUsed(); // Paper - delay chunk unloads
|
2018-07-16 22:08:09 +02:00
|
|
|
return this.chunk != null;
|
2018-08-26 20:11:49 +02:00
|
|
|
}
|
|
|
|
}
|
2016-06-19 05:33:57 +02:00
|
|
|
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
2018-12-17 06:18:06 +01:00
|
|
|
index 3d17ad646..c3ac66d35 100644
|
2016-06-19 05:33:57 +02:00
|
|
|
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
2018-12-17 06:18:06 +01:00
|
|
|
@@ -456,7 +456,13 @@ public class PlayerChunkMap {
|
2016-06-19 05:33:57 +02:00
|
|
|
Chunk chunk = playerchunk.f();
|
|
|
|
|
|
|
|
if (chunk != null) {
|
2018-12-17 06:18:06 +01:00
|
|
|
- this.getWorld().getChunkProvider().unload(chunk);
|
2016-06-19 05:33:57 +02:00
|
|
|
+ // Paper start - delay chunk unloads
|
|
|
|
+ if (world.paperConfig.delayChunkUnloadsBy <= 0) {
|
2018-12-17 06:18:06 +01:00
|
|
|
+ this.getWorld().getChunkProvider().unload(chunk);
|
2016-06-19 05:33:57 +02:00
|
|
|
+ } else {
|
|
|
|
+ chunk.scheduledForUnload = System.currentTimeMillis();
|
|
|
|
+ }
|
|
|
|
+ // Paper end
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
2018-05-30 22:31:55 +02:00
|
|
|
diff --git a/src/main/java/net/minecraft/server/World.java b/src/main/java/net/minecraft/server/World.java
|
2018-12-23 18:04:13 +01:00
|
|
|
index c484493b0..9a0e5342d 100644
|
2018-05-30 22:31:55 +02:00
|
|
|
--- a/src/main/java/net/minecraft/server/World.java
|
|
|
|
+++ b/src/main/java/net/minecraft/server/World.java
|
2018-12-17 06:18:06 +01:00
|
|
|
@@ -1292,7 +1292,13 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
|
2018-08-26 20:11:49 +02:00
|
|
|
if (!tileentity.x() && tileentity.hasWorld()) {
|
2018-05-30 22:31:55 +02:00
|
|
|
BlockPosition blockposition = tileentity.getPosition();
|
|
|
|
|
2018-07-16 22:08:09 +02:00
|
|
|
- if (this.isLoaded(blockposition) && this.K.a(blockposition)) {
|
2018-05-30 22:31:55 +02:00
|
|
|
+ // 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)
|
2018-08-26 20:11:49 +02:00
|
|
|
+ shouldTick = shouldTick && chunk.scheduledForUnload == null;
|
2018-07-16 22:08:09 +02:00
|
|
|
+ if (shouldTick && this.K.a(blockposition)) {
|
2018-05-30 22:31:55 +02:00
|
|
|
+ // Paper end
|
|
|
|
try {
|
|
|
|
this.methodProfiler.a(() -> {
|
2018-07-16 22:08:09 +02:00
|
|
|
return String.valueOf(TileEntityTypes.a(tileentity.C()));
|
2016-06-19 05:33:57 +02:00
|
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
2018-12-23 18:04:13 +01:00
|
|
|
index ff1ccbd64..3e71cdcdc 100644
|
2016-06-19 05:33:57 +02:00
|
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
2018-12-23 18:04:13 +01:00
|
|
|
@@ -1750,7 +1750,7 @@ public class CraftWorld implements World {
|
2018-12-17 06:18:06 +01:00
|
|
|
ChunkProviderServer cps = world.getChunkProvider();
|
2016-06-19 05:33:57 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2018-05-30 22:31:55 +02:00
|
|
|
diff --git a/src/main/java/org/spigotmc/ActivationRange.java b/src/main/java/org/spigotmc/ActivationRange.java
|
2018-12-08 11:09:55 +01:00
|
|
|
index d08ef3fe1..081789a8f 100644
|
2018-05-30 22:31:55 +02:00
|
|
|
--- a/src/main/java/org/spigotmc/ActivationRange.java
|
|
|
|
+++ b/src/main/java/org/spigotmc/ActivationRange.java
|
2018-11-09 04:43:38 +01:00
|
|
|
@@ -323,6 +323,11 @@ public class ActivationRange
|
2018-05-30 22:31:55 +02:00
|
|
|
{
|
|
|
|
isActive = false;
|
|
|
|
}
|
|
|
|
+ // Paper start - Skip ticking in chunks scheduled for unload
|
2018-08-26 20:11:49 +02:00
|
|
|
+ else if (entity.world.paperConfig.skipEntityTickingInChunksScheduledForUnload && (chunk == null || chunk.scheduledForUnload != null)) {
|
2018-05-30 22:31:55 +02:00
|
|
|
+ isActive = false;
|
2018-08-26 20:11:49 +02:00
|
|
|
+ }
|
2018-05-30 22:31:55 +02:00
|
|
|
+ // Paper end
|
|
|
|
return isActive;
|
|
|
|
}
|
|
|
|
}
|
2016-06-19 05:33:57 +02:00
|
|
|
--
|
2018-12-23 18:04:13 +01:00
|
|
|
2.20.1
|
2016-06-19 05:33:57 +02:00
|
|
|
|