From 3dc5ad343fbcd025a13592d137e40abe6ca4ab5b Mon Sep 17 00:00:00 2001 From: Aikar Date: Sat, 20 Jun 2020 02:37:21 -0400 Subject: [PATCH] Improvements to chunk priority / bug fixes ensure we add missing player tickets even if already full status remove the player ticket throttler entirely... causes a lot of issues and our system handles the role that it was serving now too. increase max delays on farther out chunks load delay remove -5 priority delay for distant chunks seemed it applied at weird times. ensure if delay distance manager tick ever got left lingering it unsets on a chunk load. Fixes #3572 --- ...k-Priority-Urgency-System-for-Chunks.patch | 83 ++++++++++--------- .../0537-Optimize-Light-Engine.patch | 8 +- 2 files changed, 46 insertions(+), 45 deletions(-) diff --git a/Spigot-Server-Patches/0528-Implement-Chunk-Priority-Urgency-System-for-Chunks.patch b/Spigot-Server-Patches/0528-Implement-Chunk-Priority-Urgency-System-for-Chunks.patch index 7045778a75..cfeeb180e3 100644 --- a/Spigot-Server-Patches/0528-Implement-Chunk-Priority-Urgency-System-for-Chunks.patch +++ b/Spigot-Server-Patches/0528-Implement-Chunk-Priority-Urgency-System-for-Chunks.patch @@ -90,7 +90,7 @@ index f617636a22167b06ac8073aa25efd8c7099155f0..0f40793f004639822b9d40521cd21ec5 return new BlockPosition(this.x << 4, 0, this.z << 4); } diff --git a/src/main/java/net/minecraft/server/ChunkMapDistance.java b/src/main/java/net/minecraft/server/ChunkMapDistance.java -index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..02d07d3ff5c3b824047402ff1f58aa338a46c254 100644 +index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..f7be94e801e58a39e0efcc813d95bbd613afce03 100644 --- a/src/main/java/net/minecraft/server/ChunkMapDistance.java +++ b/src/main/java/net/minecraft/server/ChunkMapDistance.java @@ -23,6 +23,7 @@ import java.util.concurrent.Executor; @@ -121,13 +121,13 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..02d07d3ff5c3b824047402ff1f58aa33 // Paper start if (!this.pendingChunkUpdates.isEmpty()) { -+ this.pollingPendingChunkUpdates = true; ++ this.pollingPendingChunkUpdates = true; try { while(!this.pendingChunkUpdates.isEmpty()) { PlayerChunk remove = this.pendingChunkUpdates.remove(); remove.isUpdateQueued = false; remove.a(playerchunkmap); } -+ this.pollingPendingChunkUpdates = false; ++ } finally { this.pollingPendingChunkUpdates = false; } // Paper end return true; } else { @@ -163,7 +163,7 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..02d07d3ff5c3b824047402ff1f58aa33 return removed; // CraftBukkit } -@@ -182,6 +191,116 @@ public abstract class ChunkMapDistance { +@@ -182,6 +191,113 @@ public abstract class ChunkMapDistance { this.addTicketAtLevel(tickettype, chunkcoordintpair, i, t0); } @@ -201,16 +201,13 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..02d07d3ff5c3b824047402ff1f58aa33 + AsyncCatcher.catchOp("ChunkMapDistance::addPriorityTicket"); + long pair = coords.pair(); + PlayerChunk chunk = chunkMap.getUpdatingChunk(pair); -+ if (chunk != null && chunk.isFullChunkReady()) { ++ if (chunk != null && chunk.isFullChunkReady() && chunk.getTicketLevel() <= 33) { + return false; + } + if (chunk != null && chunk.getTicketLevel() > 33 && chunkMap.playerViewDistanceNoTickMap.getObjectsInRange(pair) != null) { + Ticket ticket = new Ticket<>(TicketType.PLAYER, 33, coords); + addTicket(pair, ticket); + } -+ if (getChunkPriority(coords) >= priority) { -+ return false; -+ } + + boolean success; + if (!(success = updatePriorityTicket(coords, ticketType, priority))) { @@ -280,7 +277,7 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..02d07d3ff5c3b824047402ff1f58aa33 public boolean addTicketAtLevel(TicketType ticketType, ChunkCoordIntPair chunkcoordintpair, int level, T identifier) { return this.addTicket(chunkcoordintpair.pair(), new Ticket<>(ticketType, level, identifier)); // CraftBukkit end -@@ -384,24 +503,29 @@ public abstract class ChunkMapDistance { +@@ -384,24 +500,26 @@ public abstract class ChunkMapDistance { Ticket ticket = new Ticket<>(TicketType.PLAYER, 33, new ChunkCoordIntPair(i)); // Paper - no-tick view distance if (flag1) { @@ -289,12 +286,8 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..02d07d3ff5c3b824047402ff1f58aa33 - if (this.c(this.c(i))) { + // Paper start - smarter ticket delay based on frustum and distance + scheduleChunkLoad(i, MinecraftServer.currentTick, j, (priority) -> { -+ ChunkMapDistance.this.j.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error -+ if (priority < 5 && this.c(this.c(i))) { -+ // Skip throttle for near chunks -+ ChunkMapDistance.this.addTicket(i, ticket); -+ ChunkMapDistance.this.l.add(i); -+ } else if (this.c(this.c(i))) { // Copy c(c()) stuff below ++ //ChunkMapDistance.this.j.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error ++ if (this.c(this.c(i))) { // Copy c(c()) stuff below + // Paper end ChunkMapDistance.this.addTicket(i, ticket); ChunkMapDistance.this.l.add(i); @@ -304,11 +297,13 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..02d07d3ff5c3b824047402ff1f58aa33 } - - }); - }, i, () -> { +- }, i, () -> { - return j; - })); -+ return Math.min(PlayerChunkMap.GOLDEN_TICKET, (priority <= 6 ? 20 : 30) + priority); // Paper - delay new ticket adds to avoid spamming the queue -+ })); }); // Paper ++ //}, i, () -> { ++ //return Math.min(PlayerChunkMap.GOLDEN_TICKET, (priority <= 6 ? 20 : 30) + priority); // Paper - delay new ticket adds to avoid spamming the queue ++ //})); // Paper ++ }); // Paper } else { ChunkMapDistance.this.k.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error ChunkMapDistance.this.m.execute(() -> { @@ -317,7 +312,7 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..02d07d3ff5c3b824047402ff1f58aa33 }); }, i, true)); } -@@ -409,6 +533,99 @@ public abstract class ChunkMapDistance { +@@ -409,6 +527,99 @@ public abstract class ChunkMapDistance { } @@ -380,8 +375,8 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..02d07d3ff5c3b824047402ff1f58aa33 + } + if (minDist > 4) { + int desiredTimeDelayMax = isFront ? -+ (minDist < 10 ? 10 : 15) : // Front -+ (minDist < 10 ? 15 : 30); // Back ++ (minDist < 10 ? 10 : 20) : // Front ++ (minDist < 10 ? 20 : 40); // Back + desireDelay += (desiredTimeDelayMax * 20) * (minDist / 32); + } + } else { @@ -409,7 +404,7 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..02d07d3ff5c3b824047402ff1f58aa33 + if (delay <= 0) { + task.accept((int) minDist); + } else { -+ MCUtil.scheduleTask((int) Math.min(delay, minDist >= 10 ? 40 : (minDist < 6 ? 10 : 20)), () -> scheduleChunkLoad(i, startTick, initialDistance, task), "Player Ticket Delayer"); ++ MCUtil.scheduleTask((int) Math.min(delay, minDist >= 10 ? 40 : (minDist < 6 ? 5 : 20)), () -> scheduleChunkLoad(i, startTick, initialDistance, task), "Player Ticket Delayer"); + } + } + // Paper end @@ -418,7 +413,7 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..02d07d3ff5c3b824047402ff1f58aa33 public void a() { super.a(); diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index 7a275bf3260f9fbefc41883c5ebdc1eb2196daf0..340d6e992786e8877243ccb472b462e88ec1e6fb 100644 +index 7a275bf3260f9fbefc41883c5ebdc1eb2196daf0..81a200ea4c533744890b6e19dd0d83f57351906c 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java @@ -432,6 +432,26 @@ public class ChunkProviderServer extends IChunkProvider { @@ -466,7 +461,7 @@ index 7a275bf3260f9fbefc41883c5ebdc1eb2196daf0..340d6e992786e8877243ccb472b462e8 } // Paper ichunkaccess = (IChunkAccess) ((Either) completablefuture.join()).map((ichunkaccess1) -> { return ichunkaccess1; -@@ -527,9 +551,10 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -527,13 +551,15 @@ public class ChunkProviderServer extends IChunkProvider { PlayerChunk.State currentChunkState = PlayerChunk.getChunkState(playerchunk.getTicketLevel()); currentlyUnloading = (oldChunkState.isAtLeast(PlayerChunk.State.BORDER) && !currentChunkState.isAtLeast(PlayerChunk.State.BORDER)); } @@ -478,7 +473,12 @@ index 7a275bf3260f9fbefc41883c5ebdc1eb2196daf0..340d6e992786e8877243ccb472b462e8 if (this.a(playerchunk, l)) { GameProfilerFiller gameprofilerfiller = this.world.getMethodProfiler(); -@@ -542,8 +567,13 @@ public class ChunkProviderServer extends IChunkProvider { + gameprofilerfiller.enter("chunkLoad"); ++ chunkMapDistance.delayDistanceManagerTick = false; // Paper - ensure this is never false + this.tickDistanceManager(); + playerchunk = this.getChunk(k); + gameprofilerfiller.exit(); +@@ -542,12 +568,17 @@ public class ChunkProviderServer extends IChunkProvider { } } } @@ -494,7 +494,12 @@ index 7a275bf3260f9fbefc41883c5ebdc1eb2196daf0..340d6e992786e8877243ccb472b462e8 } private boolean a(@Nullable PlayerChunk playerchunk, int i) { -@@ -593,7 +623,8 @@ public class ChunkProviderServer extends IChunkProvider { +- return playerchunk == null || playerchunk.oldTicketLevel > i; // CraftBukkit using oldTicketLevel for isLoaded checks ++ return playerchunk == null || playerchunk.getTicketLevel() > i; // CraftBukkit using oldTicketLevel for isLoaded checks - Paper - keep vanilla check + } + + public boolean isLoaded(int i, int j) { +@@ -593,7 +624,8 @@ public class ChunkProviderServer extends IChunkProvider { return this.serverThreadQueue.executeNext(); } @@ -559,7 +564,7 @@ index ce0bf608b71cf492fc31e89a360ecd83fa5c23a6..87d58002116f361d8255d79fc0dbd120 chunkData.addProperty("queued-for-unload", chunkMap.unloadQueue.contains(playerChunk.location.pair())); chunkData.addProperty("status", status == null ? "unloaded" : status.toString()); diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java -index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..04dcb79c6033f1dec62c5df49937a4ef067a2cb8 100644 +index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..bc5e380aa37101382c359f1c9a25803e09cd238c 100644 --- a/src/main/java/net/minecraft/server/PlayerChunk.java +++ b/src/main/java/net/minecraft/server/PlayerChunk.java @@ -26,8 +26,8 @@ public class PlayerChunk { @@ -581,7 +586,7 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..04dcb79c6033f1dec62c5df49937a4ef long lastAutoSaveTime; // Paper - incremental autosave long inactiveTimeStart; // Paper - incremental autosave -@@ -67,6 +68,124 @@ public class PlayerChunk { +@@ -67,6 +68,120 @@ public class PlayerChunk { return null; } // Paper end - no-tick view distance @@ -606,11 +611,7 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..04dcb79c6033f1dec62c5df49937a4ef + if (priorityBoost == ChunkMapDistance.URGENT_PRIORITY) { + return 2; // Urgent - ticket level isn't always 31 so 33-30 = 3, but allow 1 more tasks to go below this for dependents + } -+ int basePriority = ticketLevel - priorityBoost; -+ if (ticketLevel >= 33 && priorityBoost == 0 && (neighborPriority >= 34 || neighborPriorities.isEmpty())) { -+ basePriority += 5; -+ } -+ return basePriority; ++ return ticketLevel - priorityBoost; + } + + private int getNeighborsPriority() { @@ -706,7 +707,7 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..04dcb79c6033f1dec62c5df49937a4ef public PlayerChunk(ChunkCoordIntPair chunkcoordintpair, int i, LightEngine lightengine, PlayerChunk.c playerchunk_c, PlayerChunk.d playerchunk_d) { this.statusFutures = new AtomicReferenceArray(PlayerChunk.CHUNK_STATUSES.size()); -@@ -165,6 +284,15 @@ public class PlayerChunk { +@@ -165,6 +280,15 @@ public class PlayerChunk { } return null; } @@ -722,7 +723,7 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..04dcb79c6033f1dec62c5df49937a4ef // Paper end public CompletableFuture> getStatusFutureUnchecked(ChunkStatus chunkstatus) { -@@ -418,6 +546,7 @@ public class PlayerChunk { +@@ -418,6 +542,7 @@ public class PlayerChunk { return this.n; } @@ -730,7 +731,7 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..04dcb79c6033f1dec62c5df49937a4ef private void d(int i) { this.n = i; } -@@ -436,7 +565,7 @@ public class PlayerChunk { +@@ -436,7 +561,7 @@ public class PlayerChunk { // CraftBukkit start // ChunkUnloadEvent: Called before the chunk is unloaded: isChunkLoaded is still true and chunk can still be modified by plugins. if (playerchunk_state.isAtLeast(PlayerChunk.State.BORDER) && !playerchunk_state1.isAtLeast(PlayerChunk.State.BORDER)) { @@ -739,7 +740,7 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..04dcb79c6033f1dec62c5df49937a4ef Chunk chunk = (Chunk)either.left().orElse(null); if (chunk != null) { playerchunkmap.callbackExecutor.execute(() -> { -@@ -501,12 +630,13 @@ public class PlayerChunk { +@@ -501,12 +626,13 @@ public class PlayerChunk { if (!flag2 && flag3) { // Paper start - cache ticking ready status int expectCreateCount = ++this.fullChunkCreateCount; @@ -754,7 +755,7 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..04dcb79c6033f1dec62c5df49937a4ef } -@@ -531,7 +661,7 @@ public class PlayerChunk { +@@ -531,7 +657,7 @@ public class PlayerChunk { if (!flag4 && flag5) { // Paper start - cache ticking ready status @@ -763,7 +764,7 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..04dcb79c6033f1dec62c5df49937a4ef if (either.left().isPresent()) { // note: Here is a very good place to add callbacks to logic waiting on this. Chunk tickingChunk = either.left().get(); -@@ -562,7 +692,7 @@ public class PlayerChunk { +@@ -562,7 +688,7 @@ public class PlayerChunk { } // Paper start - cache ticking ready status @@ -772,7 +773,7 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..04dcb79c6033f1dec62c5df49937a4ef if (either.left().isPresent()) { // note: Here is a very good place to add callbacks to logic waiting on this. Chunk entityTickingChunk = either.left().get(); -@@ -581,13 +711,29 @@ public class PlayerChunk { +@@ -581,13 +707,29 @@ public class PlayerChunk { this.entityTickingFuture.complete(PlayerChunk.UNLOADED_CHUNK); this.isEntityTickingReady = false; // Paper - cache chunk ticking stage this.entityTickingFuture = PlayerChunk.UNLOADED_CHUNK_FUTURE; } @@ -805,7 +806,7 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..04dcb79c6033f1dec62c5df49937a4ef Chunk chunk = (Chunk)either.left().orElse(null); if (chunk != null) { playerchunkmap.callbackExecutor.execute(() -> { -@@ -669,6 +815,7 @@ public class PlayerChunk { +@@ -669,6 +811,7 @@ public class PlayerChunk { public interface c { diff --git a/Spigot-Server-Patches/0537-Optimize-Light-Engine.patch b/Spigot-Server-Patches/0537-Optimize-Light-Engine.patch index a79b4f92c8..9894648b2d 100644 --- a/Spigot-Server-Patches/0537-Optimize-Light-Engine.patch +++ b/Spigot-Server-Patches/0537-Optimize-Light-Engine.patch @@ -38,10 +38,10 @@ index d051a54aa04326f84e211cd68ddd2bb209230770..bd7a92599b4182739aafef9eeaaf8665 return this.j; } diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index 340d6e992786e8877243ccb472b462e88ec1e6fb..451803d3f575b7fcd7ce0891bc1e2c86c2aa2832 100644 +index 81a200ea4c533744890b6e19dd0d83f57351906c..46d62aa414b340a14302e52bb882be08b58fa9a9 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java -@@ -1089,7 +1089,7 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -1090,7 +1090,7 @@ public class ChunkProviderServer extends IChunkProvider { if (ChunkProviderServer.this.tickDistanceManager()) { return true; } else { @@ -1332,10 +1332,10 @@ index 8cedfdd820cc02a76607b53e0b054fc74654f907..a9795394c9b17f9f0ce4c4f9c8f51a48 private static final int nibbleBucketSizeMultiplier = Integer.getInteger("Paper.nibbleBucketSize", 3072); private static final int maxPoolSize = Integer.getInteger("Paper.maxNibblePoolSize", (int) Math.min(6, Math.max(1, Runtime.getRuntime().maxMemory() / 1024 / 1024 / 1024)) * (nibbleBucketSizeMultiplier * 8)); diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java -index f8820f24075e7f42f67426fc9ecf5238f4499b72..0ef55c49235f8e024268b5411eeaf4ddc76c921d 100644 +index d04c8cdcc16ea7f0a49dc5720ddc8e47be0b634c..9c1be2e2d42701a96e8c40b377d13f5c0e92bf06 100644 --- a/src/main/java/net/minecraft/server/PlayerChunk.java +++ b/src/main/java/net/minecraft/server/PlayerChunk.java -@@ -729,6 +729,7 @@ public class PlayerChunk { +@@ -725,6 +725,7 @@ public class PlayerChunk { ioPriority = com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGH_PRIORITY; } chunkMap.world.asyncChunkTaskManager.raisePriority(location.x, location.z, ioPriority);