PaperMC/Remapped-Spigot-Server-Patches/0492-Delay-Chunk-Unloads-based-on-Player-Movement.patch

108 lines
5.7 KiB
Diff
Raw Normal View History

2021-06-11 13:56:17 +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 6463d3e4837d032a35654a035f42b8a805e0e286..1655bca0502e7b871de4addaa163536d86547a02 100644
--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
+++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java
@@ -637,4 +637,13 @@ public class PaperWorldConfig {
private void viewDistance() {
this.noTickViewDistance = this.getInt("viewdistances.no-tick-view-distance", -1);
}
+
+ 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;
+ }
+ }
}
diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java
index e41f388e8350010a471410436adf15a906f07e97..e0241b9d60cd2b72f8fb774f1ab4753dfd615184 100644
--- a/src/main/java/net/minecraft/server/level/DistanceManager.java
+++ b/src/main/java/net/minecraft/server/level/DistanceManager.java
@@ -185,6 +185,27 @@ public abstract class DistanceManager {
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.setCurrentTick(this.ticketTickCounter);
+ 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 c0bfe136ccb9ad4fc0f8ccdd703254205213ec8e..f7898bd7806684d2c068898cecbf835d834df461 100644
--- a/src/main/java/net/minecraft/server/level/Ticket.java
+++ b/src/main/java/net/minecraft/server/level/Ticket.java
@@ -9,11 +9,13 @@ public final class Ticket<T> implements Comparable<Ticket<?>> {
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 int priority = 0; // Paper
+ 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
}
public int compareTo(Ticket<?> ticket) {
@@ -63,7 +65,7 @@ public final class Ticket<T> implements Comparable<Ticket<?>> {
}
protected boolean timedOut(long currentTick) {
- long j = this.type.timeout();
+ long j = delayUnloadBy; // Paper
return j != 0L && currentTick - this.createdTick > j;
}
diff --git a/src/main/java/net/minecraft/server/level/TicketType.java b/src/main/java/net/minecraft/server/level/TicketType.java
index 2444f6f676db543509b14e8c882491dc3f41b264..531ebf1bafec2b295af9f6dfec8f4b6466688287 100644
--- a/src/main/java/net/minecraft/server/level/TicketType.java
+++ b/src/main/java/net/minecraft/server/level/TicketType.java
@@ -30,6 +30,7 @@ public class TicketType<T> {
public static final TicketType<Long> ASYNC_LOAD = create("async_load", Long::compareTo); // Paper
public static final TicketType<ChunkPos> PRIORITY = create("priority", Comparator.comparingLong(ChunkPos::toLong), 300); // Paper
public static final TicketType<ChunkPos> URGENT = create("urgent", Comparator.comparingLong(ChunkPos::toLong), 300); // Paper
+ public static final TicketType<Long> DELAY_UNLOAD = create("delay_unload", Long::compareTo, 300); // Paper
public static <T> TicketType<T> create(String name, Comparator<T> comparator) {
return new TicketType<>(name, comparator, 0L);