b62dfa0bf9
Upstream has released updates that appears to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: 39ce5d3a SPIGOT-4399: ItemMeta.equals broken with AttributeModifiers CraftBukkit Changes: 1cf8b5dc SPIGOT-4400: Populators running on existing chunks 116cb9a1 SPIGOT-4399: Add attribute modifier equality test 5ee1c18a SPIGOT-4398: Set ASM7_EXPERIMENTAL flag
184 lines
8.7 KiB
Diff
184 lines
8.7 KiB
Diff
From e46d08efd3f5e429c3d0cabb76bf8456bd03324b 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 ff1a2046f6..0cd15c17e8 100644
|
|
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
|
|
@@ -296,4 +296,18 @@ public class PaperWorldConfig {
|
|
preventTntFromMovingInWater = getBoolean("prevent-tnt-from-moving-in-water", false);
|
|
log("Prevent TNT from moving in water: " + preventTntFromMovingInWater);
|
|
}
|
|
+
|
|
+ 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 41d3aaa80b..824727ec66 100644
|
|
--- a/src/main/java/net/minecraft/server/Chunk.java
|
|
+++ b/src/main/java/net/minecraft/server/Chunk.java
|
|
@@ -37,6 +37,7 @@ public class Chunk implements IChunkAccess {
|
|
private boolean i;public boolean isLoaded() { return i; } // Paper - OBFHELPER
|
|
public final World world;
|
|
public final Map<HeightMap.Type, HeightMap> heightMap;
|
|
+ public Long scheduledForUnload; // Paper - delay chunk unloads
|
|
public final int locX;
|
|
public final int locZ;
|
|
private boolean l; public boolean needsGapCheck() { return l; } // Paper - OBFHELPER
|
|
diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
index 2d10f4aa37..719d5deb2c 100644
|
|
--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
+++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java
|
|
@@ -306,6 +306,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.chunkScheduler.a(booleansupplier);
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java
|
|
index ac0e90eeca..3f4a8f21c0 100644
|
|
--- a/src/main/java/net/minecraft/server/PlayerChunk.java
|
|
+++ b/src/main/java/net/minecraft/server/PlayerChunk.java
|
|
@@ -33,8 +33,16 @@ public class PlayerChunk {
|
|
public void run() {
|
|
loadInProgress = false;
|
|
PlayerChunk.this.chunk = PlayerChunk.this.playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(location.x, location.z, true, true);
|
|
+ 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) {
|
|
@@ -44,6 +52,7 @@ public class PlayerChunk {
|
|
|
|
chunkproviderserver.a(i, j);
|
|
this.chunk = chunkproviderserver.getChunkAt(i, j, true, false);
|
|
+ markChunkUsed(); // Paper - delay chunk unloads
|
|
}
|
|
|
|
public ChunkCoordIntPair a() {
|
|
@@ -85,6 +94,7 @@ public class PlayerChunk {
|
|
return true;
|
|
} else {
|
|
this.chunk = this.playerChunkMap.getWorld().getChunkProviderServer().getChunkAt(this.location.x, this.location.z, true, flag);
|
|
+ markChunkUsed(); // Paper - delay chunk unloads
|
|
return this.chunk != null;
|
|
}
|
|
}
|
|
diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
index a69d510dd1..7b67fa3208 100644
|
|
--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
+++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java
|
|
@@ -460,7 +460,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 785f020652..d31101861c 100644
|
|
--- a/src/main/java/net/minecraft/server/World.java
|
|
+++ b/src/main/java/net/minecraft/server/World.java
|
|
@@ -1342,7 +1342,13 @@ public abstract class World implements IEntityAccess, GeneratorAccess, IIBlockAc
|
|
if (!tileentity.x() && tileentity.hasWorld()) {
|
|
BlockPosition blockposition = tileentity.getPosition();
|
|
|
|
- if (this.isLoaded(blockposition) && this.K.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.scheduledForUnload == null;
|
|
+ if (shouldTick && this.K.a(blockposition)) {
|
|
+ // Paper end
|
|
try {
|
|
this.methodProfiler.a(() -> {
|
|
return String.valueOf(TileEntityTypes.a(tileentity.C()));
|
|
diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
index 72d1a0f51d..3536433d14 100644
|
|
--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java
|
|
@@ -1633,7 +1633,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 12040596df..f9bb19fed6 100644
|
|
--- a/src/main/java/org/spigotmc/ActivationRange.java
|
|
+++ b/src/main/java/org/spigotmc/ActivationRange.java
|
|
@@ -284,6 +284,11 @@ public class ActivationRange
|
|
{
|
|
isActive = false;
|
|
}
|
|
+ // Paper start - Skip ticking in chunks scheduled for unload
|
|
+ else if (entity.world.paperConfig.skipEntityTickingInChunksScheduledForUnload && (chunk == null || chunk.scheduledForUnload != null)) {
|
|
+ isActive = false;
|
|
+ }
|
|
+ // Paper end
|
|
return isActive;
|
|
}
|
|
}
|
|
--
|
|
2.19.0
|
|
|