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 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 { expMergeMaxValue = getInt("experience-merge-max-value", -1); log("Experience Merge Max Value: " + expMergeMaxValue); } + + 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/DistanceManager.java +++ b/src/main/java/net/minecraft/server/level/DistanceManager.java @@ -0,0 +0,0 @@ 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.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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/Ticket.java +++ b/src/main/java/net/minecraft/server/level/Ticket.java @@ -0,0 +0,0 @@ public final class Ticket<T> implements Comparable<Ticket<?>> { private final int ticketLevel; public final T key; public long createdTick; + 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 @@ -0,0 +0,0 @@ public final class Ticket<T> implements Comparable<Ticket<?>> { } 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 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/TicketType.java +++ b/src/main/java/net/minecraft/server/level/TicketType.java @@ -0,0 +0,0 @@ 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 + 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);