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 7b3d3b3c6c73fb146c3be29aaaac77fee5824f91..845f105457d659a4bd88d4a8ce91b20d6abb7865 100644 --- a/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java +++ b/src/main/java/com/destroystokyo/paper/PaperWorldConfig.java @@ -550,6 +550,15 @@ public class PaperWorldConfig { lightQueueSize = getInt("light-queue-size", lightQueueSize); } + 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 java.util.Map altItemDespawnRateMap; private void altItemDespawnRate() { diff --git a/src/main/java/net/minecraft/server/level/DistanceManager.java b/src/main/java/net/minecraft/server/level/DistanceManager.java index 95f195980e28bb59f43e5ca1d5e79ebe8c3ddaea..84dc1e94b4f7b8315d8422634dd49b1f85044d18 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java @@ -197,6 +197,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 delayUnload = new Ticket(TicketType.DELAY_UNLOAD, 33, i); + delayUnload.delayUnloadBy = delayChunkUnloadsBy; + delayUnload.setCreatedTick(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 ffc43e5d3d0563c9e9c171064511b2c65ddf67e1..f1128f0d4a9a0241ac6c9bc18dd13b431c616bb1 100644 --- 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 implements Comparable> { private final int ticketLevel; public final T key; public long createdTick; + public long delayUnloadBy; // Paper protected Ticket(TicketType 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 implements Comparable> { } protected boolean timedOut(long currentTick) { - long l = this.type.timeout(); + long l = delayUnloadBy; // Paper return l != 0L && currentTick - this.createdTick > l; } } 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 --- 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 { public static final TicketType UNKNOWN = TicketType.create("unknown", Comparator.comparingLong(ChunkPos::toLong), 1); public static final TicketType PLUGIN = TicketType.create("plugin", (a, b) -> 0); // CraftBukkit public static final TicketType PLUGIN_TICKET = TicketType.create("plugin_ticket", (plugin1, plugin2) -> plugin1.getClass().getName().compareTo(plugin2.getClass().getName())); // CraftBukkit + public static final TicketType DELAY_UNLOAD = create("delay_unload", Long::compareTo, 300); // Paper public static TicketType create(String name, Comparator argumentComparator) { return new TicketType<>(name, argumentComparator, 0L);