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 9078488a8..4ef1f2dc6 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..f7be94e801e58a39e0efcc813d95bbd613afce03 100644 +index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..35a4999b2c34ae62cba042885db25dd1837cb127 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; @@ -101,6 +101,15 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..f7be94e801e58a39e0efcc813d95bbd6 public abstract class ChunkMapDistance { +@@ -46,7 +47,7 @@ public abstract class ChunkMapDistance { + private final ChunkTaskQueueSorter i; + private final Mailbox> j; + private final Mailbox k; +- private final LongSet l = new LongOpenHashSet(); ++ private final LongSet l = new LongOpenHashSet(); LongSet getOnPlayerTicketAddQueue() { return l; } // Paper - OBFHELPER + private final Executor m; + private long currentTick; + @@ -84,6 +85,7 @@ public abstract class ChunkMapDistance { } @@ -163,7 +172,7 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..f7be94e801e58a39e0efcc813d95bbd6 return removed; // CraftBukkit } -@@ -182,6 +191,113 @@ public abstract class ChunkMapDistance { +@@ -182,6 +191,135 @@ public abstract class ChunkMapDistance { this.addTicketAtLevel(tickettype, chunkcoordintpair, i, t0); } @@ -181,8 +190,10 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..f7be94e801e58a39e0efcc813d95bbd6 + + public void markAreaHighPriority(ChunkCoordIntPair center, int priority, int radius) { + delayDistanceManagerTick = true; ++ priority = Math.min(URGENT_PRIORITY - 1, Math.max(1, priority)); ++ int finalPriority = priority; + MCUtil.getSpiralOutChunks(center.asPosition(), radius).forEach(coords -> { -+ addPriorityTicket(coords, TicketType.PRIORITY, priority); ++ addPriorityTicket(coords, TicketType.PRIORITY, finalPriority); + }); + delayDistanceManagerTick = false; + chunkMap.world.getChunkProvider().tickDistanceManager(); @@ -197,17 +208,37 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..f7be94e801e58a39e0efcc813d95bbd6 + chunkMap.world.getChunkProvider().tickDistanceManager(); + } + ++ private boolean hasPlayerTicket(ChunkCoordIntPair coords, int level) { ++ ArraySetSorted> tickets = this.tickets.get(coords.pair()); ++ if (tickets == null || tickets.isEmpty()) { ++ return false; ++ } ++ for (Ticket ticket : tickets) { ++ if (ticket.getTicketType() == TicketType.PLAYER && ticket.getTicketLevel() == level) { ++ return true; ++ } ++ } ++ ++ return false; ++ } ++ + private boolean addPriorityTicket(ChunkCoordIntPair coords, TicketType ticketType, int priority) { + AsyncCatcher.catchOp("ChunkMapDistance::addPriorityTicket"); + long pair = coords.pair(); + PlayerChunk chunk = chunkMap.getUpdatingChunk(pair); -+ if (chunk != null && chunk.isFullChunkReady() && chunk.getTicketLevel() <= 33) { -+ return false; -+ } -+ if (chunk != null && chunk.getTicketLevel() > 33 && chunkMap.playerViewDistanceNoTickMap.getObjectsInRange(pair) != null) { ++ boolean needsTicket = chunkMap.playerViewDistanceNoTickMap.getObjectsInRange(pair) != null && !hasPlayerTicket(coords, 33); ++ ++ if (needsTicket) { + Ticket ticket = new Ticket<>(TicketType.PLAYER, 33, coords); ++ getOnPlayerTicketAddQueue().add(pair); + addTicket(pair, ticket); + } ++ if ((chunk != null && chunk.isFullChunkReady())) { ++ if (needsTicket) { ++ chunkMap.world.getChunkProvider().tickDistanceManager(); ++ } ++ return needsTicket; ++ } + + boolean success; + if (!(success = updatePriorityTicket(coords, ticketType, priority))) { @@ -277,51 +308,75 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..f7be94e801e58a39e0efcc813d95bbd6 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 +500,26 @@ public abstract class ChunkMapDistance { - Ticket ticket = new Ticket<>(TicketType.PLAYER, 33, new ChunkCoordIntPair(i)); // Paper - no-tick view distance +@@ -381,27 +519,51 @@ public abstract class ChunkMapDistance { + + private void a(long i, int j, boolean flag, boolean flag1) { + if (flag != flag1) { +- Ticket ticket = new Ticket<>(TicketType.PLAYER, 33, new ChunkCoordIntPair(i)); // Paper - no-tick view distance ++ ChunkCoordIntPair coords = new ChunkCoordIntPair(i); // Paper ++ Ticket ticket = new Ticket<>(TicketType.PLAYER, 33, coords); // Paper - no-tick view distance if (flag1) { -- ChunkMapDistance.this.j.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error -- ChunkMapDistance.this.m.execute(() -> { ++ scheduleChunkLoad(i, MinecraftServer.currentTick, j, (priority) -> { // Paper - smarter ticket delay based on frustum and distance ++ // Paper start - recheck its still valid if not cancel ++ if (!isChunkInRange(i)) { ++ ChunkMapDistance.this.k.a(ChunkTaskQueueSorter.a(() -> { ++ ChunkMapDistance.this.m.execute(() -> { ++ ChunkMapDistance.this.removeTicket(i, ticket); ++ ChunkMapDistance.this.clearPriorityTickets(coords); ++ }); ++ }, i, false)); ++ return; ++ } ++ // abort early if we got a ticket already ++ if (hasPlayerTicket(coords, 33)) return; ++ // skip player ticket throttle for near chunks ++ if (priority <= 3) { ++ ChunkMapDistance.this.addTicket(i, ticket); ++ ChunkMapDistance.this.l.add(i); ++ return; ++ } ++ // Paper end + ChunkMapDistance.this.j.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error + ChunkMapDistance.this.m.execute(() -> { - 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 (this.c(this.c(i))) { // Copy c(c()) stuff below -+ // Paper end ++ if (isChunkInRange(i)) { if (!hasPlayerTicket(coords, 33)) { // Paper - high priority might of already added it ChunkMapDistance.this.addTicket(i, ticket); ChunkMapDistance.this.l.add(i); - } else { +- } else { ++ } ++ } else { // Paper ChunkMapDistance.this.k.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error }, i, false)); } -- -- }); -- }, i, () -> { + + }); + }, i, () -> { - return j; -- })); -+ //}, i, () -> { -+ //return Math.min(PlayerChunkMap.GOLDEN_TICKET, (priority <= 6 ? 20 : 30) + priority); // Paper - delay new ticket adds to avoid spamming the queue -+ //})); // Paper ++ return Math.min(PlayerChunkMap.GOLDEN_TICKET, priority); // Paper + })); + }); // Paper } else { ChunkMapDistance.this.k.a(ChunkTaskQueueSorter.a(() -> { // CraftBukkit - decompile error ChunkMapDistance.this.m.execute(() -> { ChunkMapDistance.this.removeTicket(i, ticket); -+ ChunkMapDistance.this.clearPriorityTickets(new ChunkCoordIntPair(i)); // Paper ++ ChunkMapDistance.this.clearPriorityTickets(coords); // Paper }); }, i, true)); } -@@ -409,6 +527,99 @@ public abstract class ChunkMapDistance { +@@ -409,6 +571,102 @@ public abstract class ChunkMapDistance { } + // Paper start - smart scheduling of player tickets ++ private boolean isChunkInRange(long i) { ++ return this.isLoadedChunkLevel(this.getChunkLevel(i)); ++ } + public void scheduleChunkLoad(long i, long startTick, int initialDistance, java.util.function.Consumer task) { + long elapsed = MinecraftServer.currentTick - startTick; + ChunkCoordIntPair chunkPos = new ChunkCoordIntPair(i); + PlayerChunk updatingChunk = chunkMap.getUpdatingChunk(i); -+ if ((updatingChunk != null && updatingChunk.isFullChunkReady()) || !this.c(this.c(i)) || getChunkPriority(chunkPos) > 0) { // Copied from above ++ if ((updatingChunk != null && updatingChunk.isFullChunkReady()) || !isChunkInRange(i) || getChunkPriority(chunkPos) > 0) { // Copied from above + // no longer needed + task.accept(1); + return; @@ -355,8 +410,7 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..f7be94e801e58a39e0efcc813d95bbd6 + + double dist = Math.min(frontDist, center); + if (!isFront) { -+ -+ ChunkCoordIntPair pointInBack = player.getChunkInFront(-5); ++ ChunkCoordIntPair pointInBack = player.getChunkInFront(-7); + pos.setValues(pointInBack.x << 4, 0, pointInBack.z << 4); + double backDist = MCUtil.distanceSq(pos, blockPos); + if (frontDist < backDist) { @@ -375,8 +429,8 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..f7be94e801e58a39e0efcc813d95bbd6 + } + if (minDist > 4) { + int desiredTimeDelayMax = isFront ? -+ (minDist < 10 ? 10 : 20) : // Front -+ (minDist < 10 ? 20 : 40); // Back ++ (minDist < 10 ? 7 : 15) : // Front ++ (minDist < 10 ? 15 : 45); // Back + desireDelay += (desiredTimeDelayMax * 20) * (minDist / 32); + } + } else { @@ -389,7 +443,7 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..f7be94e801e58a39e0efcc813d95bbd6 + for (int x = -1; x <= 1; x++) { + for (int z = -1; z <= 1; z++) { + if (x == 0 && z == 0) continue; -+ long pair = new ChunkCoordIntPair(chunkPos.x + x, chunkPos.z + z).pair(); ++ long pair = ChunkCoordIntPair.pair(chunkPos.x + x, chunkPos.z + z); + PlayerChunk neighbor = chunkMap.getUpdatingChunk(pair); + ChunkStatus current = neighbor != null ? neighbor.getChunkHolderStatus() : null; + if (current != null && current.isAtLeastStatus(ChunkStatus.LIGHT)) { @@ -398,13 +452,14 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..f7be94e801e58a39e0efcc813d95bbd6 + } + } + if (!hasAnyNeighbor) { -+ delay += 10; ++ delay += 20; + } + } + if (delay <= 0) { + task.accept((int) minDist); + } else { -+ MCUtil.scheduleTask((int) Math.min(delay, minDist >= 10 ? 40 : (minDist < 6 ? 5 : 20)), () -> scheduleChunkLoad(i, startTick, initialDistance, task), "Player Ticket Delayer"); ++ int taskDelay = (int) Math.min(delay, minDist >= 10 ? 40 : (minDist < 6 ? 5 : 20)); ++ MCUtil.scheduleTask(taskDelay, () -> scheduleChunkLoad(i, startTick, initialDistance, task), "Player Ticket Delayer"); + } + } + // Paper end @@ -412,6 +467,22 @@ index 7702fbefa598bce7e6a2d287f7ec36b78a62bff8..f7be94e801e58a39e0efcc813d95bbd6 @Override public void a() { super.a(); +@@ -440,6 +698,7 @@ public abstract class ChunkMapDistance { + + } + ++ private boolean isLoadedChunkLevel(int i) { return c(i); } // Paper - OBFHELPER + private boolean c(int i) { + return i <= this.e - 2; + } +@@ -456,6 +715,7 @@ public abstract class ChunkMapDistance { + this.a.defaultReturnValue((byte) (i + 2)); + } + ++ protected final int getChunkLevel(long i) { return c(i); } // Paper - OBFHELPER + @Override + protected int c(long i) { + return this.a.get(i); diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java index 7a275bf3260f9fbefc41883c5ebdc1eb2196daf0..b6a7e475c6ebe499c641db5967adb1674323a517 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java @@ -501,18 +572,23 @@ index 7a275bf3260f9fbefc41883c5ebdc1eb2196daf0..b6a7e475c6ebe499c641db5967adb167 boolean flag1 = this.playerChunkMap.b(); diff --git a/src/main/java/net/minecraft/server/EntityPlayer.java b/src/main/java/net/minecraft/server/EntityPlayer.java -index 07a6fc3d88e7d44bfab7f3d6a0eef7dc132ab422..4ed4ad6bc3b4ab6702ca500dc26e889dca6ed2d7 100644 +index 07a6fc3d88e7d44bfab7f3d6a0eef7dc132ab422..39072ebdc9e4be2bb762d81a8bd542dbdb8f6371 100644 --- a/src/main/java/net/minecraft/server/EntityPlayer.java +++ b/src/main/java/net/minecraft/server/EntityPlayer.java -@@ -55,6 +55,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { +@@ -55,6 +55,12 @@ public class EntityPlayer extends EntityHuman implements ICrafting { private int lastArmorScored = Integer.MIN_VALUE; private int lastExpLevelScored = Integer.MIN_VALUE; private int lastExpTotalScored = Integer.MIN_VALUE; + public long lastHighPriorityChecked; // Paper ++ public void forceCheckHighPriority() { ++ lastHighPriorityChecked = -1; ++ getWorldServer().getChunkProvider().playerChunkMap.checkHighPriorityChunks(this); ++ } ++ public boolean isRealPlayer; // Paper private float lastHealthSent = -1.0E8F; private int lastFoodSent = -99999999; private boolean lastSentSaturationZero = true; -@@ -132,6 +133,21 @@ public class EntityPlayer extends EntityHuman implements ICrafting { +@@ -132,6 +138,21 @@ public class EntityPlayer extends EntityHuman implements ICrafting { this.maxHealthCache = this.getMaxHealth(); this.cachedSingleMobDistanceMap = new com.destroystokyo.paper.util.PooledHashSets.PooledObjectLinkedOpenHashSet<>(this); // Paper } @@ -534,11 +610,11 @@ index 07a6fc3d88e7d44bfab7f3d6a0eef7dc132ab422..4ed4ad6bc3b4ab6702ca500dc26e889d // Yes, this doesn't match Vanilla, but it's the best we can do for now. // If this is an issue, PRs are welcome -@@ -441,6 +457,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { +@@ -441,6 +462,7 @@ public class EntityPlayer extends EntityHuman implements ICrafting { if (valid && (!this.isSpectator() || this.world.isLoaded(new BlockPosition(this)))) { // Paper - don't tick dead players that are not in the world currently (pending respawn) super.tick(); } -+ if (valid && isAlive()) ((WorldServer)world).getChunkProvider().playerChunkMap.checkHighPriorityChunks(this); // Paper ++ if (valid && isAlive() && playerConnection != null) ((WorldServer)world).getChunkProvider().playerChunkMap.checkHighPriorityChunks(this); // Paper for (int i = 0; i < this.inventory.getSize(); ++i) { ItemStack itemstack = this.inventory.getItem(i); @@ -555,7 +631,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..bc5e380aa37101382c359f1c9a25803e09cd238c 100644 +index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..52da9c78c0cc2b21533a1477a25a3dda492700e4 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 { @@ -698,7 +774,7 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..bc5e380aa37101382c359f1c9a25803e 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 +280,15 @@ public class PlayerChunk { +@@ -165,6 +280,18 @@ public class PlayerChunk { } return null; } @@ -709,12 +785,15 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..bc5e380aa37101382c359f1c9a25803e + return CHUNK_STATUSES.get(status.getStatusIndex() + 1); + } + public CompletableFuture> getStatusFutureUncheckedMain(ChunkStatus chunkstatus) { -+ return MCUtil.ensureMain(getStatusFutureUnchecked(chunkstatus)); ++ return ensureMain(getStatusFutureUnchecked(chunkstatus)); ++ } ++ public CompletableFuture ensureMain(CompletableFuture future) { ++ return future.thenApplyAsync(r -> r, chunkMap.mainInvokingExecutor); + } // Paper end public CompletableFuture> getStatusFutureUnchecked(ChunkStatus chunkstatus) { -@@ -418,6 +542,7 @@ public class PlayerChunk { +@@ -418,6 +545,7 @@ public class PlayerChunk { return this.n; } @@ -722,7 +801,7 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..bc5e380aa37101382c359f1c9a25803e private void d(int i) { this.n = i; } -@@ -436,7 +561,7 @@ public class PlayerChunk { +@@ -436,7 +564,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)) { @@ -731,12 +810,12 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..bc5e380aa37101382c359f1c9a25803e Chunk chunk = (Chunk)either.left().orElse(null); if (chunk != null) { playerchunkmap.callbackExecutor.execute(() -> { -@@ -501,12 +626,13 @@ public class PlayerChunk { +@@ -501,12 +629,13 @@ public class PlayerChunk { if (!flag2 && flag3) { // Paper start - cache ticking ready status int expectCreateCount = ++this.fullChunkCreateCount; - this.fullChunkFuture = playerchunkmap.b(this); this.fullChunkFuture.thenAccept((either) -> { -+ this.fullChunkFuture = playerchunkmap.b(this); MCUtil.ensureMain(this.fullChunkFuture).thenAccept((either) -> { // Paper - ensure main ++ this.fullChunkFuture = playerchunkmap.b(this); ensureMain(this.fullChunkFuture).thenAccept((either) -> { // Paper - ensure main if (either.left().isPresent() && PlayerChunk.this.fullChunkCreateCount == expectCreateCount) { // note: Here is a very good place to add callbacks to logic waiting on this. Chunk fullChunk = either.left().get(); @@ -746,25 +825,25 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..bc5e380aa37101382c359f1c9a25803e } -@@ -531,7 +657,7 @@ public class PlayerChunk { +@@ -531,7 +660,7 @@ public class PlayerChunk { if (!flag4 && flag5) { // Paper start - cache ticking ready status - this.tickingFuture = playerchunkmap.a(this); this.tickingFuture.thenAccept((either) -> { -+ this.tickingFuture = playerchunkmap.a(this); MCUtil.ensureMain(this.tickingFuture).thenAccept((either) -> { // Paper - ensure main ++ this.tickingFuture = playerchunkmap.a(this); ensureMain(this.tickingFuture).thenAccept((either) -> { // Paper - ensure main 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 +688,7 @@ public class PlayerChunk { +@@ -562,7 +691,7 @@ public class PlayerChunk { } // Paper start - cache ticking ready status - this.entityTickingFuture = playerchunkmap.b(this.location); this.entityTickingFuture.thenAccept((either) -> { -+ this.entityTickingFuture = playerchunkmap.b(this.location); MCUtil.ensureMain(this.entityTickingFuture).thenAccept((either) -> { // Paper ensureMain ++ this.entityTickingFuture = playerchunkmap.b(this.location); ensureMain(this.entityTickingFuture).thenAccept((either) -> { // Paper ensureMain 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 +707,29 @@ public class PlayerChunk { +@@ -581,13 +710,29 @@ public class PlayerChunk { this.entityTickingFuture.complete(PlayerChunk.UNLOADED_CHUNK); this.isEntityTickingReady = false; // Paper - cache chunk ticking stage this.entityTickingFuture = PlayerChunk.UNLOADED_CHUNK_FUTURE; } @@ -797,7 +876,7 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..bc5e380aa37101382c359f1c9a25803e Chunk chunk = (Chunk)either.left().orElse(null); if (chunk != null) { playerchunkmap.callbackExecutor.execute(() -> { -@@ -669,6 +811,7 @@ public class PlayerChunk { +@@ -669,6 +814,7 @@ public class PlayerChunk { public interface c { @@ -806,7 +885,7 @@ index aeca6b2b9d5d73aeb6dc639b5cad2f2533a2de44..bc5e380aa37101382c359f1c9a25803e } diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java -index 0aa14bfca6e1845eb6e9f5bd4e0e36335fa7f532..6c0dbad8e06b02b32dcff518cc2a5f7c8c1c316c 100644 +index 0aa14bfca6e1845eb6e9f5bd4e0e36335fa7f532..3139d55bb801b6c433de7274be4a1d0c0fd1eef7 100644 --- a/src/main/java/net/minecraft/server/PlayerChunkMap.java +++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java @@ -50,6 +50,7 @@ import org.apache.commons.lang3.mutable.MutableBoolean; @@ -841,17 +920,20 @@ index 0aa14bfca6e1845eb6e9f5bd4e0e36335fa7f532..6c0dbad8e06b02b32dcff518cc2a5f7c if (newState.size() != 1) { return; } -@@ -393,7 +397,8 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { +@@ -393,7 +397,11 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { } ChunkCoordIntPair chunkPos = new ChunkCoordIntPair(rangeX, rangeZ); PlayerChunkMap.this.world.getChunkProvider().removeTicketAtLevel(TicketType.PLAYER, chunkPos, 31, chunkPos); // entity ticking level, TODO check on update - }); + PlayerChunkMap.this.world.getChunkProvider().clearPriorityTickets(chunkPos); -+ }, (player, prevPos, newPos) -> checkHighPriorityChunks(player)); ++ }, (player, prevPos, newPos) -> { ++ player.lastHighPriorityChecked = -1; // reset and recheck ++ checkHighPriorityChunks(player); ++ }); this.playerViewDistanceNoTickMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets); this.playerViewDistanceBroadcastMap = new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets, (EntityPlayer player, int rangeX, int rangeZ, int currPosX, int currPosZ, int prevPosX, int prevPosZ, -@@ -410,6 +415,101 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { +@@ -410,6 +418,116 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { }); // Paper end - no-tick view distance } @@ -878,33 +960,41 @@ index 0aa14bfca6e1845eb6e9f5bd4e0e36335fa7f532..6c0dbad8e06b02b32dcff518cc2a5f7c + return playerchunk == null || unloadQueue.contains(playerchunk.location.pair()); + } + ++ private void updateChunkPriorityMap(it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap map, long chunk, int level) { ++ int prev = map.getOrDefault(chunk, -1); ++ if (level > prev) { ++ map.put(chunk, level); ++ } ++ } ++ + public void checkHighPriorityChunks(EntityPlayer player) { + int currentTick = MinecraftServer.currentTick; -+ if (currentTick - player.lastHighPriorityChecked < 20) { ++ if (currentTick - player.lastHighPriorityChecked < 20 || !player.isRealPlayer) { // weed out fake players + return; + } + player.lastHighPriorityChecked = currentTick; ++ it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap priorities = new it.unimi.dsi.fastutil.longs.Long2IntOpenHashMap(); + + int viewDistance = getEffectiveNoTickViewDistance(); -+ chunkDistanceManager.delayDistanceManagerTick = true; + BlockPosition.PooledBlockPosition pos = BlockPosition.PooledBlockPosition.acquire(); + + // Prioritize circular near + double playerChunkX = MathHelper.floor(player.locX()) >> 4; + double playerChunkZ = MathHelper.floor(player.locZ()) >> 4; + pos.setValues(player.locX(), 0, player.locZ()); ++ double twoThirdModifier = 2D / 3D; + MCUtil.getSpiralOutChunks(pos, Math.min(6, viewDistance)).forEach(coord -> { + if (shouldSkipPrioritization(coord)) return; + + double dist = MCUtil.distance(playerChunkX, 0, playerChunkZ, coord.x, 0, coord.z); + // Prioritize immediate + if (dist <= 4 * 4) { -+ chunkDistanceManager.markHighPriority(coord, (int) (27 - Math.sqrt(dist))); ++ updateChunkPriorityMap(priorities, coord.pair(), (int) (27 - Math.sqrt(dist))); + return; + } + + // Prioritize nearby chunks -+ chunkDistanceManager.markHighPriority(coord, (int) (16 - Math.sqrt(dist*(2D/3D)))); ++ updateChunkPriorityMap(priorities, coord.pair(), (int) (20 - Math.sqrt(dist) * twoThirdModifier)); + }); + + // Prioritize Frustum near 3 @@ -913,7 +1003,8 @@ index 0aa14bfca6e1845eb6e9f5bd4e0e36335fa7f532..6c0dbad8e06b02b32dcff518cc2a5f7c + MCUtil.getSpiralOutChunks(pos, Math.min(5, viewDistance)).forEach(coord -> { + if (shouldSkipPrioritization(coord)) return; + -+ chunkDistanceManager.markHighPriority(coord, 26); ++ double dist = MCUtil.distance(playerChunkX, 0, playerChunkZ, coord.x, 0, coord.z); ++ updateChunkPriorityMap(priorities, coord.pair(), (int) (25 - Math.sqrt(dist) * twoThirdModifier)); + }); + + // Prioritize Frustum near 5 @@ -923,7 +1014,8 @@ index 0aa14bfca6e1845eb6e9f5bd4e0e36335fa7f532..6c0dbad8e06b02b32dcff518cc2a5f7c + MCUtil.getSpiralOutChunks(pos, 4).forEach(coord -> { + if (shouldSkipPrioritization(coord)) return; + -+ chunkDistanceManager.markHighPriority(coord, 20); ++ double dist = MCUtil.distance(playerChunkX, 0, playerChunkZ, coord.x, 0, coord.z); ++ updateChunkPriorityMap(priorities, coord.pair(), (int) (25 - Math.sqrt(dist) * twoThirdModifier)); + }); + } + @@ -935,13 +1027,18 @@ index 0aa14bfca6e1845eb6e9f5bd4e0e36335fa7f532..6c0dbad8e06b02b32dcff518cc2a5f7c + if (shouldSkipPrioritization(coord)) { + return; + } -+ chunkDistanceManager.markHighPriority(coord, 15); ++ double dist = MCUtil.distance(playerChunkX, 0, playerChunkZ, coord.x, 0, coord.z); ++ updateChunkPriorityMap(priorities, coord.pair(), (int) (25 - Math.sqrt(dist) * twoThirdModifier)); + }); + } + + pos.close(); ++ if (priorities.isEmpty()) return; ++ chunkDistanceManager.delayDistanceManagerTick = true; ++ priorities.long2IntEntrySet().fastForEach(entry -> chunkDistanceManager.markHighPriority(new ChunkCoordIntPair(entry.getLongKey()), entry.getIntValue())); + chunkDistanceManager.delayDistanceManagerTick = false; + world.getChunkProvider().tickDistanceManager(); ++ + } + + private boolean shouldSkipPrioritization(ChunkCoordIntPair coord) { @@ -953,7 +1050,7 @@ index 0aa14bfca6e1845eb6e9f5bd4e0e36335fa7f532..6c0dbad8e06b02b32dcff518cc2a5f7c public void updatePlayerMobTypeMap(Entity entity) { if (!this.world.paperConfig.perPlayerMobSpawns) { -@@ -539,6 +639,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { +@@ -539,6 +657,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { List>> list = Lists.newArrayList(); int j = chunkcoordintpair.x; int k = chunkcoordintpair.z; @@ -961,7 +1058,7 @@ index 0aa14bfca6e1845eb6e9f5bd4e0e36335fa7f532..6c0dbad8e06b02b32dcff518cc2a5f7c for (int l = -i; l <= i; ++l) { for (int i1 = -i; i1 <= i; ++i1) { -@@ -557,6 +658,14 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { +@@ -557,6 +676,14 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { ChunkStatus chunkstatus = (ChunkStatus) intfunction.apply(j1); CompletableFuture> completablefuture = playerchunk.a(chunkstatus, this); @@ -976,7 +1073,7 @@ index 0aa14bfca6e1845eb6e9f5bd4e0e36335fa7f532..6c0dbad8e06b02b32dcff518cc2a5f7c list.add(completablefuture); } -@@ -1022,14 +1131,22 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { +@@ -1022,14 +1149,22 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { }; CompletableFuture chunkSaveFuture = this.world.asyncChunkTaskManager.getChunkSaveFuture(chunkcoordintpair.x, chunkcoordintpair.z); @@ -1004,7 +1101,7 @@ index 0aa14bfca6e1845eb6e9f5bd4e0e36335fa7f532..6c0dbad8e06b02b32dcff518cc2a5f7c return ret; // Paper end } -@@ -1158,7 +1275,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { +@@ -1158,7 +1293,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { long i = playerchunk.i().pair(); playerchunk.getClass(); @@ -1014,19 +1111,19 @@ index 0aa14bfca6e1845eb6e9f5bd4e0e36335fa7f532..6c0dbad8e06b02b32dcff518cc2a5f7c } diff --git a/src/main/java/net/minecraft/server/PlayerConnection.java b/src/main/java/net/minecraft/server/PlayerConnection.java -index d52fbda79fe1c52d3ddb53c0f1c1f521d7620702..7123e197c7ed01afd4fbf7aa0760611373039a13 100644 +index d52fbda79fe1c52d3ddb53c0f1c1f521d7620702..f9cb87a3be35575ecf3362b10dc7fe5ebadb56ec 100644 --- a/src/main/java/net/minecraft/server/PlayerConnection.java +++ b/src/main/java/net/minecraft/server/PlayerConnection.java -@@ -1277,6 +1277,7 @@ public class PlayerConnection implements PacketListenerPlayIn { - // CraftBukkit end - +@@ -1279,6 +1279,7 @@ public class PlayerConnection implements PacketListenerPlayIn { this.A = this.e; -+ this.player.getWorldServer().getChunkProvider().markAreaHighPriority(new ChunkCoordIntPair(MathHelper.floor(d1) >> 4, MathHelper.floor(d3) >> 4), 28, 3); // Paper - load area high priority this.player.setLocation(d0, d1, d2, f, f1); this.syncPosition(); // Paper ++ this.player.forceCheckHighPriority(); // Paper this.player.playerConnection.sendPacket(new PacketPlayOutPosition(d0 - d3, d1 - d4, d2 - d5, f - f2, f1 - f3, set, this.teleportAwait)); + } + diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java -index 6daca5c0ffd1d84f9a25cd106e8992a055dfb912..b0585346bf5125bebc482246bbb91c4b08c55816 100644 +index 6daca5c0ffd1d84f9a25cd106e8992a055dfb912..f133e7baf958b031819c2c72ccd21c52ba9a683d 100644 --- a/src/main/java/net/minecraft/server/PlayerList.java +++ b/src/main/java/net/minecraft/server/PlayerList.java @@ -174,8 +174,8 @@ public abstract class PlayerList { @@ -1048,11 +1145,19 @@ index 6daca5c0ffd1d84f9a25cd106e8992a055dfb912..b0585346bf5125bebc482246bbb91c4b }; }); } -@@ -764,6 +763,7 @@ public abstract class PlayerList { +@@ -585,6 +584,7 @@ public abstract class PlayerList { + SocketAddress socketaddress = loginlistener.networkManager.getSocketAddress(); + + EntityPlayer entity = new EntityPlayer(this.server, this.server.getWorldServer(DimensionManager.OVERWORLD), gameprofile, new PlayerInteractManager(this.server.getWorldServer(DimensionManager.OVERWORLD))); ++ entity.isRealPlayer = true; // Paper + Player player = entity.getBukkitEntity(); + PlayerLoginEvent event = new PlayerLoginEvent(player, hostname, ((java.net.InetSocketAddress) socketaddress).getAddress(), ((java.net.InetSocketAddress) loginlistener.networkManager.getRawAddress()).getAddress()); + +@@ -764,6 +764,7 @@ public abstract class PlayerList { // CraftBukkit end worldserver.getChunkProvider().addTicket(TicketType.POST_TELEPORT, new ChunkCoordIntPair(location.getBlockX() >> 4, location.getBlockZ() >> 4), 1, entityplayer.getId()); // Paper -+ worldserver.getChunkProvider().markAreaHighPriority(new ChunkCoordIntPair(location.getBlockX() >> 4, location.getBlockZ() >> 4), 28, 3); // Paper - load area at high priority ++ entityplayer1.forceCheckHighPriority(); // Player while (avoidSuffocation && !worldserver.getCubes(entityplayer1) && entityplayer1.locY() < 256.0D) { entityplayer1.setPosition(entityplayer1.locX(), entityplayer1.locY() + 1.0D, entityplayer1.locZ()); } diff --git a/Spigot-Server-Patches/0530-Optimize-sending-packets-to-nearby-locations-sounds-.patch b/Spigot-Server-Patches/0530-Optimize-sending-packets-to-nearby-locations-sounds-.patch index 5cd96e93a..fe477cdf8 100644 --- a/Spigot-Server-Patches/0530-Optimize-sending-packets-to-nearby-locations-sounds-.patch +++ b/Spigot-Server-Patches/0530-Optimize-sending-packets-to-nearby-locations-sounds-.patch @@ -11,10 +11,10 @@ This will drastically cut down on packet sending cost for worlds with lots of players in them. diff --git a/src/main/java/net/minecraft/server/PlayerList.java b/src/main/java/net/minecraft/server/PlayerList.java -index 6daca5c0ffd1d84f9a25cd106e8992a055dfb912..c03395ce824ec1305b3cabb63343922d32a02b85 100644 +index f133e7baf958b031819c2c72ccd21c52ba9a683d..ab8247eb790be2084be7544f72e5b6661151905d 100644 --- a/src/main/java/net/minecraft/server/PlayerList.java +++ b/src/main/java/net/minecraft/server/PlayerList.java -@@ -1030,11 +1030,30 @@ public abstract class PlayerList { +@@ -1031,11 +1031,30 @@ public abstract class PlayerList { world = (WorldServer) entityhuman.world; } @@ -51,7 +51,7 @@ index 6daca5c0ffd1d84f9a25cd106e8992a055dfb912..c03395ce824ec1305b3cabb63343922d // CraftBukkit start - Test if player receiving packet can see the source of the packet diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java -index 9e32e2db10f5faaa3c5f4adc5cbc2c1a2e4d3073..854c97bddb711ed252c2ae8398247641fdfb10be 100644 +index aaf85a1497de98522e3a01d4f81a267c4b0cc087..2c9acffe5a62af43ff4f4ccdb6962929d645e226 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -70,6 +70,7 @@ public class WorldServer extends World { diff --git a/Spigot-Server-Patches/0532-Improve-Chunk-Status-Transition-Speed.patch b/Spigot-Server-Patches/0532-Improve-Chunk-Status-Transition-Speed.patch index 1c5220364..85c0553f6 100644 --- a/Spigot-Server-Patches/0532-Improve-Chunk-Status-Transition-Speed.patch +++ b/Spigot-Server-Patches/0532-Improve-Chunk-Status-Transition-Speed.patch @@ -36,7 +36,7 @@ scenario / path: Previously would have hopped to SERVER around 12+ times there extra. diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java -index 04dcb79c6033f1dec62c5df49937a4ef067a2cb8..f8820f24075e7f42f67426fc9ecf5238f4499b72 100644 +index 52da9c78c0cc2b21533a1477a25a3dda492700e4..69899c100dd86c6c4795013364472336327ce036 100644 --- a/src/main/java/net/minecraft/server/PlayerChunk.java +++ b/src/main/java/net/minecraft/server/PlayerChunk.java @@ -56,6 +56,13 @@ public class PlayerChunk { @@ -54,7 +54,7 @@ index 04dcb79c6033f1dec62c5df49937a4ef067a2cb8..f8820f24075e7f42f67426fc9ecf5238 // Paper start - no-tick view distance public final Chunk getSendingChunk() { diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java -index 6c0dbad8e06b02b32dcff518cc2a5f7c8c1c316c..394cea57b3871c2e11d1f7e0e9546df64ff3bafe 100644 +index 3139d55bb801b6c433de7274be4a1d0c0fd1eef7..98adcb6390105a183d66975ed9659906b609ce08 100644 --- a/src/main/java/net/minecraft/server/PlayerChunkMap.java +++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java @@ -88,6 +88,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { @@ -81,7 +81,7 @@ index 6c0dbad8e06b02b32dcff518cc2a5f7c8c1c316c..394cea57b3871c2e11d1f7e0e9546df6 ThreadedMailbox threadedmailbox = ThreadedMailbox.a(executor, "worldgen"); iasynctaskhandler.getClass(); -@@ -706,7 +716,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { +@@ -724,7 +734,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { return either.mapLeft((list) -> { return (Chunk) list.get(list.size() / 2); }); @@ -90,7 +90,7 @@ index 6c0dbad8e06b02b32dcff518cc2a5f7c8c1c316c..394cea57b3871c2e11d1f7e0e9546df6 } @Nullable -@@ -1056,7 +1066,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { +@@ -1074,7 +1084,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { IChunkAccess ichunkaccess = (IChunkAccess) optional.get(); if (ichunkaccess.getChunkStatus().b(chunkstatus)) { @@ -99,7 +99,7 @@ index 6c0dbad8e06b02b32dcff518cc2a5f7c8c1c316c..394cea57b3871c2e11d1f7e0e9546df6 if (chunkstatus == ChunkStatus.LIGHT) { completablefuture1 = this.b(playerchunk, chunkstatus); -@@ -1072,7 +1082,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { +@@ -1090,7 +1100,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { return this.b(playerchunk, chunkstatus); } } @@ -108,7 +108,7 @@ index 6c0dbad8e06b02b32dcff518cc2a5f7c8c1c316c..394cea57b3871c2e11d1f7e0e9546df6 } } -@@ -1183,6 +1193,12 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { +@@ -1201,6 +1211,12 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { return CompletableFuture.completedFuture(Either.right(playerchunk_failure)); }); }, (runnable) -> { diff --git a/Spigot-Server-Patches/0537-Optimize-Light-Engine.patch b/Spigot-Server-Patches/0537-Optimize-Light-Engine.patch index 3318fd147..4b00c7d98 100644 --- a/Spigot-Server-Patches/0537-Optimize-Light-Engine.patch +++ b/Spigot-Server-Patches/0537-Optimize-Light-Engine.patch @@ -1337,10 +1337,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 d04c8cdcc16ea7f0a49dc5720ddc8e47be0b634c..9c1be2e2d42701a96e8c40b377d13f5c0e92bf06 100644 +index 69899c100dd86c6c4795013364472336327ce036..2edb4904d3071aa9de6517c375410b814a45cfbe 100644 --- a/src/main/java/net/minecraft/server/PlayerChunk.java +++ b/src/main/java/net/minecraft/server/PlayerChunk.java -@@ -725,6 +725,7 @@ public class PlayerChunk { +@@ -728,6 +728,7 @@ public class PlayerChunk { ioPriority = com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGH_PRIORITY; } chunkMap.world.asyncChunkTaskManager.raisePriority(location.x, location.z, ioPriority); @@ -1349,10 +1349,10 @@ index d04c8cdcc16ea7f0a49dc5720ddc8e47be0b634c..9c1be2e2d42701a96e8c40b377d13f5c if (getCurrentPriority() != priority) { this.w.a(this.location, this::getCurrentPriority, priority, this::setPriority); // use preferred priority diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java -index 394cea57b3871c2e11d1f7e0e9546df64ff3bafe..8abf276a325cbc3a863fb89276526790c4de2692 100644 +index 98adcb6390105a183d66975ed9659906b609ce08..201221df63d4ec8e704fee9126240891f2b1c37d 100644 --- a/src/main/java/net/minecraft/server/PlayerChunkMap.java +++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java -@@ -629,6 +629,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { +@@ -647,6 +647,7 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { // Paper end }