108 lines
5.7 KiB
Diff
108 lines
5.7 KiB
Diff
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);
|