Paper/patches/server/0446-Delay-Chunk-Unloads-based-on-Player-Movement.patch

110 lines
5.9 KiB
Diff
Raw Normal View History

2021-06-11 14:02:28 +02:00
From 0000000000000000000000000000000000000000 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 will be handled by the ticket expiry process.
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 3bc6329d3ea48966cb99e792f9b35e2d2d71a34b..1f4d0d3493e748f52eb3b679c0a8a1306c0cc8b4 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -495,6 +495,15 @@ public class PaperWorldConfig {
2021-06-11 14:02:28 +02:00
this.noTickViewDistance = this.getInt("viewdistances.no-tick-view-distance", -1);
}
2021-06-11 14:02:28 +02:00
+ 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 *= 20;
+ }
+ }
+
public boolean altItemDespawnRateEnabled;
public Map<Material, Integer> altItemDespawnRateMap;
private void altItemDespawnRate() {
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
index 577b391dcba1db712c1e2c83296e1c87b3e34ab2..d94241bcca4f2fd5e464a860bd356af504dc68b7 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
@@ -181,6 +181,27 @@ public abstract class DistanceManager {
2021-06-11 14:02:28 +02:00
boolean removed = false; // CraftBukkit
if (arraysetsorted.remove(ticket)) {
removed = true; // CraftBukkit
+ // Paper start - delay chunk unloads for player tickets
+ long delayChunkUnloadsBy = chunkMap.level.paperConfig.delayChunkUnloadsBy;
+ if (ticket.getType() == TicketType.PLAYER && delayChunkUnloadsBy > 0) {
+ boolean hasPlayer = false;
+ for (Ticket<?> ticket1 : arraysetsorted) {
+ if (ticket1.getType() == TicketType.PLAYER) {
+ hasPlayer = true;
+ break;
+ }
+ }
+ ChunkHolder playerChunk = chunkMap.getUpdatingChunkIfPresent(i);
+ if (!hasPlayer && playerChunk != null && playerChunk.isFullChunkReady()) {
+ Ticket<Long> delayUnload = new Ticket<Long>(TicketType.DELAY_UNLOAD, 33, i);
+ delayUnload.delayUnloadBy = delayChunkUnloadsBy;
+ delayUnload.setCreatedTick(this.ticketTickCounter);
2021-06-11 14:02:28 +02:00
+ arraysetsorted.remove(delayUnload);
+ // refresh ticket
+ arraysetsorted.add(delayUnload);
+ }
+ }
+ // Paper end
}
if (arraysetsorted.isEmpty()) {
diff --git a/src/main/java/net/minecraft/server/level/Ticket.java b/src/main/java/net/minecraft/server/level/Ticket.java
index 8b0c6e1a649400908dbb674dfb4cdd1aa0ce1d38..a7aa7a9038d4812a9d1e4e72c4dbbbe10df15820 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/level/Ticket.java
+++ b/src/main/java/net/minecraft/server/level/Ticket.java
@@ -7,11 +7,13 @@ public final class Ticket<T> implements Comparable<Ticket<?>> {
private final int ticketLevel;
2021-06-11 14:02:28 +02:00
public final T key; public final T getObjectReason() { return this.key; } // Paper - OBFHELPER
private long createdTick; public final long getCreationTick() { return this.createdTick; } // Paper - OBFHELPER
+ public long delayUnloadBy; // Paper
protected Ticket(TicketType<T> type, int level, T argument) {
this.type = type;
this.ticketLevel = level;
this.key = argument;
+ this.delayUnloadBy = type.timeout; // Paper
}
@Override
@@ -60,7 +62,7 @@ public final class Ticket<T> implements Comparable<Ticket<?>> {
2021-06-11 14:02:28 +02:00
}
protected boolean timedOut(long currentTick) {
- long l = this.type.timeout();
+ long l = delayUnloadBy; // Paper
return l != 0L && currentTick - this.createdTick > l;
2021-06-11 14:02:28 +02:00
}
}
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java
index 78fbb4c3e52e900956ae0811aaf934c81ee5ea48..8770fe0db46b01e8b608637df4f1a669a3f4cdde 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/level/TicketType.java
+++ b/src/main/java/net/minecraft/server/level/TicketType.java
@@ -28,6 +28,7 @@ public class TicketType<T> {
public static final TicketType<ChunkPos> UNKNOWN = TicketType.create("unknown", Comparator.comparingLong(ChunkPos::toLong), 1);
public static final TicketType<Unit> PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit
public static final TicketType<org.bukkit.plugin.Plugin> PLUGIN_TICKET = TicketType.create("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // CraftBukkit
2021-06-11 14:02:28 +02:00
+ public static final TicketType<Long> DELAY_UNLOAD = create("delay_unload", Long::compareTo, 300); // Paper
public static <T> TicketType<T> create(String name, Comparator<T> argumentComparator) {
return new TicketType<>(name, argumentComparator, 0L);