diff --git a/Spigot-Server-Patches/Delay-Chunk-Unloads-based-on-Player-Movement.patch b/Spigot-Server-Patches/Delay-Chunk-Unloads-based-on-Player-Movement.patch new file mode 100644 index 000000000..9f68c9134 --- /dev/null +++ b/Spigot-Server-Patches/Delay-Chunk-Unloads-based-on-Player-Movement.patch @@ -0,0 +1,113 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java ++++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +@@ -0,0 +0,0 @@ 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/ChunkMapDistance.java b/src/main/java/net/minecraft/server/ChunkMapDistance.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/ChunkMapDistance.java ++++ b/src/main/java/net/minecraft/server/ChunkMapDistance.java +@@ -0,0 +0,0 @@ public abstract class ChunkMapDistance { + boolean removed = false; // CraftBukkit + if (arraysetsorted.remove(ticket)) { + removed = true; // CraftBukkit ++ // Paper start - delay chunk unloads for player tickets ++ long delayChunkUnloadsBy = chunkMap.world.paperConfig.delayChunkUnloadsBy; ++ if (ticket.getTicketType() == TicketType.PLAYER && delayChunkUnloadsBy > 0) { ++ boolean hasPlayer = false; ++ for (Ticket ticket1 : arraysetsorted) { ++ if (ticket1.getTicketType() == TicketType.PLAYER) { ++ hasPlayer = true; ++ break; ++ } ++ } ++ PlayerChunk playerChunk = chunkMap.getUpdatingChunk(i); ++ if (!hasPlayer && playerChunk != null && playerChunk.isFullChunkReady()) { ++ Ticket delayUnload = new Ticket(TicketType.DELAY_UNLOAD, 33, i); ++ delayUnload.delayUnloadBy = delayChunkUnloadsBy; ++ delayUnload.setCurrentTick(this.currentTick); ++ arraysetsorted.remove(delayUnload); ++ // refresh ticket ++ arraysetsorted.add(delayUnload); ++ } ++ } ++ // Paper end + } + + if (arraysetsorted.isEmpty()) { +diff --git a/src/main/java/net/minecraft/server/Ticket.java b/src/main/java/net/minecraft/server/Ticket.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/Ticket.java ++++ b/src/main/java/net/minecraft/server/Ticket.java +@@ -0,0 +0,0 @@ public final class Ticket implements Comparable> { + public final T identifier; public final T getObjectReason() { return this.identifier; } // Paper - OBFHELPER + private long d; public final long getCreationTick() { return this.d; } // Paper - OBFHELPER + public int priority = 0; // Paper ++ public long delayUnloadBy; // Paper + + protected Ticket(TicketType tickettype, int i, T t0) { + this.a = tickettype; + this.b = i; + this.identifier = t0; ++ this.delayUnloadBy = tickettype.loadPeriod; // Paper + } + + public int compareTo(Ticket ticket) { +@@ -0,0 +0,0 @@ public final class Ticket implements Comparable> { + return this.b; + } + ++ protected void setCurrentTick(long i) { a(i); } // Paper - OBFHELPER + protected void a(long i) { + this.d = i; + } + + protected boolean b(long i) { +- long j = this.a.b(); ++ long j = delayUnloadBy; // Paper + + return j != 0L && i - this.d > j; + } +diff --git a/src/main/java/net/minecraft/server/TicketType.java b/src/main/java/net/minecraft/server/TicketType.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/TicketType.java ++++ b/src/main/java/net/minecraft/server/TicketType.java +@@ -0,0 +0,0 @@ public class TicketType { + public static final TicketType ASYNC_LOAD = a("async_load", Long::compareTo); // Paper + public static final TicketType PRIORITY = a("priority", Comparator.comparingLong(ChunkCoordIntPair::pair), 300); // Paper + public static final TicketType URGENT = a("urgent", Comparator.comparingLong(ChunkCoordIntPair::pair), 300); // Paper ++ public static final TicketType DELAY_UNLOAD = a("delay_unload", Long::compareTo, 300); // Paper + + public static TicketType a(String s, Comparator comparator) { + return new TicketType<>(s, comparator, 0L);