diff --git a/Spigot-API-Patches/0132-Async-Chunks-API.patch b/Spigot-API-Patches/0132-Async-Chunks-API.patch index 67fcae029..16273413b 100644 --- a/Spigot-API-Patches/0132-Async-Chunks-API.patch +++ b/Spigot-API-Patches/0132-Async-Chunks-API.patch @@ -8,10 +8,10 @@ Adds API's to load or generate chunks asynchronously. Also adds utility methods to Entity to teleport asynchronously. diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index e5b76d59fdcc85344cf3932b38ab096155d2eec3..62aa9bd67cf652cc9fcd4ef2ced3bc48e120763d 100644 +index e5b76d59fdcc85344cf3932b38ab096155d2eec3..8fe496ad8f566183e2280582d00c3b7751f06d75 100644 --- a/src/main/java/org/bukkit/World.java +++ b/src/main/java/org/bukkit/World.java -@@ -221,6 +221,358 @@ public interface World extends PluginMessageRecipient, Metadatable { +@@ -221,6 +221,467 @@ public interface World extends PluginMessageRecipient, Metadatable { public default Chunk getChunkAt(long chunkKey) { return getChunkAt((int) chunkKey, (int) (chunkKey >> 32)); } @@ -366,15 +366,124 @@ index e5b76d59fdcc85344cf3932b38ab096155d2eec3..62aa9bd67cf652cc9fcd4ef2ced3bc48 + * @return Future that will resolve when the chunk is loaded + */ + @NotNull -+ public java.util.concurrent.CompletableFuture getChunkAtAsync(int x, int z, boolean gen); ++ public default java.util.concurrent.CompletableFuture getChunkAtAsync(int x, int z, boolean gen) { ++ return getChunkAtAsync(x, z, gen, false); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * @param loc Location to load the corresponding chunk from ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ @NotNull ++ public default java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(@NotNull Location loc) { ++ return getChunkAtAsync((int)Math.floor(loc.getX()) >> 4, (int)Math.floor(loc.getZ()) >> 4, true, true); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * @param loc Location to load the corresponding chunk from ++ * @param gen Should the chunk generate ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ @NotNull ++ public default java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(@NotNull Location loc, boolean gen) { ++ return getChunkAtAsync((int)Math.floor(loc.getX()) >> 4, (int)Math.floor(loc.getZ()) >> 4, gen, true); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * @param block Block to load the corresponding chunk from ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ @NotNull ++ public default java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(@NotNull Block block) { ++ return getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, true, true); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * @param block Block to load the corresponding chunk from ++ * @param gen Should the chunk generate ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ @NotNull ++ public default java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(@NotNull Block block, boolean gen) { ++ return getChunkAtAsync(block.getX() >> 4, block.getZ() >> 4, gen, true); ++ } ++ ++ /** ++ * Requests a {@link Chunk} to be loaded at the given coordinates ++ * ++ * This method makes no guarantee on how fast the chunk will load, ++ * and will return the chunk to the callback at a later time. ++ * ++ * You should use this method if you need a chunk but do not need it ++ * immediately, and you wish to let the server control the speed ++ * of chunk loads, keeping performance in mind. ++ * ++ * The future will always be executed synchronously ++ * on the main Server Thread. ++ * ++ * @param x X Coord ++ * @param z Z Coord ++ * @return Future that will resolve when the chunk is loaded ++ */ ++ @NotNull ++ public default java.util.concurrent.CompletableFuture getChunkAtAsyncUrgently(int x, int z) { ++ return getChunkAtAsync(x, z, true, true); ++ } ++ ++ @NotNull ++ java.util.concurrent.CompletableFuture getChunkAtAsync(int x, int z, boolean gen, boolean urgent); // Paper end /** diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index b4069dbf31587786da39f5e387a71b7bc6a5d0ae..45e0dffe60ce1f4d54b481b6b2cbee511659a5cc 100644 +index b4069dbf31587786da39f5e387a71b7bc6a5d0ae..b8e8a425a84a562ccd8431d30e39145a662c4180 100644 --- a/src/main/java/org/bukkit/entity/Entity.java +++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -155,6 +155,30 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent +@@ -155,6 +155,33 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent */ public boolean teleport(@NotNull Entity destination, @NotNull TeleportCause cause); @@ -397,7 +506,10 @@ index b4069dbf31587786da39f5e387a71b7bc6a5d0ae..45e0dffe60ce1f4d54b481b6b2cbee51 + @NotNull + public default java.util.concurrent.CompletableFuture teleportAsync(@NotNull Location loc, @NotNull TeleportCause cause) { + java.util.concurrent.CompletableFuture future = new java.util.concurrent.CompletableFuture<>(); -+ loc.getWorld().getChunkAtAsync(loc).thenAccept((chunk) -> future.complete(teleport(loc, cause))); ++ loc.getWorld().getChunkAtAsyncUrgently(loc).thenAccept((chunk) -> future.complete(teleport(loc, cause))).exceptionally(ex -> { ++ future.completeExceptionally(ex); ++ return null; ++ }); + return future; + } + // Paper end diff --git a/Spigot-API-Patches/0157-Add-sun-related-API.patch b/Spigot-API-Patches/0157-Add-sun-related-API.patch index d81cff7e9..b4c7ae239 100644 --- a/Spigot-API-Patches/0157-Add-sun-related-API.patch +++ b/Spigot-API-Patches/0157-Add-sun-related-API.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Add sun related API diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index b7ad4f566497914573ccfb595e660226dd34c273..c88f17244617b75e251811595ffc189dc81e12fb 100644 +index 42b91634a131f8705cbde96b6068d5881a393fb7..f9a5ea4fcdb87e741cf04b47d469e05f8a786155 100644 --- a/src/main/java/org/bukkit/World.java +++ b/src/main/java/org/bukkit/World.java -@@ -1646,6 +1646,16 @@ public interface World extends PluginMessageRecipient, Metadatable { +@@ -1755,6 +1755,16 @@ public interface World extends PluginMessageRecipient, Metadatable { */ public void setFullTime(long time); diff --git a/Spigot-API-Patches/0173-Entity-getEntitySpawnReason.patch b/Spigot-API-Patches/0173-Entity-getEntitySpawnReason.patch index 67ae211cd..7e528fc7e 100644 --- a/Spigot-API-Patches/0173-Entity-getEntitySpawnReason.patch +++ b/Spigot-API-Patches/0173-Entity-getEntitySpawnReason.patch @@ -10,10 +10,10 @@ persistenting Living Entity, SPAWNER for spawners, or DEFAULT since data was not stored. diff --git a/src/main/java/org/bukkit/entity/Entity.java b/src/main/java/org/bukkit/entity/Entity.java -index 45e0dffe60ce1f4d54b481b6b2cbee511659a5cc..5518ecd21435334d9148cd3e095ec06031bdd0a5 100644 +index b8e8a425a84a562ccd8431d30e39145a662c4180..3f0f38031000a4eda25584d069939f40fbfb026b 100644 --- a/src/main/java/org/bukkit/entity/Entity.java +++ b/src/main/java/org/bukkit/entity/Entity.java -@@ -649,5 +649,11 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent +@@ -652,5 +652,11 @@ public interface Entity extends Metadatable, CommandSender, Nameable, Persistent */ @NotNull Chunk getChunk(); diff --git a/Spigot-API-Patches/0203-World-view-distance-api.patch b/Spigot-API-Patches/0203-World-view-distance-api.patch index 1a2d6e705..6676931bf 100644 --- a/Spigot-API-Patches/0203-World-view-distance-api.patch +++ b/Spigot-API-Patches/0203-World-view-distance-api.patch @@ -5,10 +5,10 @@ Subject: [PATCH] World view distance api diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index db18f70ec37253232fb2cfd08ccd07d13c7c457d..421ad6a91ceb38fd62684d18f109d7cf8526605a 100644 +index 0a5865d85dfc28cb68f753878608b12afd74bc99..be4d6ca8e8ec4c2e6643eaecc19f11466e14658c 100644 --- a/src/main/java/org/bukkit/World.java +++ b/src/main/java/org/bukkit/World.java -@@ -3166,6 +3166,34 @@ public interface World extends PluginMessageRecipient, Metadatable { +@@ -3275,6 +3275,34 @@ public interface World extends PluginMessageRecipient, Metadatable { int getViewDistance(); // Spigot end diff --git a/Spigot-API-Patches/0205-Spawn-Reason-API.patch b/Spigot-API-Patches/0205-Spawn-Reason-API.patch index b9780cf4e..de7272882 100644 --- a/Spigot-API-Patches/0205-Spawn-Reason-API.patch +++ b/Spigot-API-Patches/0205-Spawn-Reason-API.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Spawn Reason API diff --git a/src/main/java/org/bukkit/World.java b/src/main/java/org/bukkit/World.java -index 421ad6a91ceb38fd62684d18f109d7cf8526605a..906ee6827dc6956b3c1657bde75ef8481e16dce2 100644 +index be4d6ca8e8ec4c2e6643eaecc19f11466e14658c..9518da825ed752c5a477ca9132de50f923f9192d 100644 --- a/src/main/java/org/bukkit/World.java +++ b/src/main/java/org/bukkit/World.java @@ -1,6 +1,8 @@ @@ -17,7 +17,7 @@ index 421ad6a91ceb38fd62684d18f109d7cf8526605a..906ee6827dc6956b3c1657bde75ef848 import org.bukkit.generator.ChunkGenerator; import java.util.ArrayList; -@@ -2037,6 +2039,12 @@ public interface World extends PluginMessageRecipient, Metadatable { +@@ -2146,6 +2148,12 @@ public interface World extends PluginMessageRecipient, Metadatable { @NotNull public T spawn(@NotNull Location location, @NotNull Class clazz) throws IllegalArgumentException; @@ -30,7 +30,7 @@ index 421ad6a91ceb38fd62684d18f109d7cf8526605a..906ee6827dc6956b3c1657bde75ef848 /** * Spawn an entity of a specific class at the given {@link Location}, with * the supplied function run before the entity is added to the world. -@@ -2054,7 +2062,28 @@ public interface World extends PluginMessageRecipient, Metadatable { +@@ -2163,7 +2171,28 @@ public interface World extends PluginMessageRecipient, Metadatable { * {@link Entity} requested cannot be spawned */ @NotNull diff --git a/Spigot-Server-Patches/0390-Asynchronous-chunk-IO-and-loading.patch b/Spigot-Server-Patches/0390-Asynchronous-chunk-IO-and-loading.patch index 99252250c..879140cf0 100644 --- a/Spigot-Server-Patches/0390-Asynchronous-chunk-IO-and-loading.patch +++ b/Spigot-Server-Patches/0390-Asynchronous-chunk-IO-and-loading.patch @@ -2305,22 +2305,33 @@ index 0000000000000000000000000000000000000000..2b20c159f6bb425be70201cf33159aa9 + +} diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index 4c9c8e483974f8869d6711626620cfd7d814d956..259af7095c453e52e7c3a8662968d96de0efbbc8 100644 +index 4c9c8e483974f8869d6711626620cfd7d814d956..cabe2a5908dd9ee721c13c1825e65a37f72361d4 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java -@@ -299,11 +299,137 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -299,11 +299,136 @@ public class ChunkProviderServer extends IChunkProvider { return playerChunk.getAvailableChunkNow(); } + + private long asyncLoadSeqCounter; + -+ public void getChunkAtAsynchronously(int x, int z, boolean gen, java.util.function.Consumer onComplete) { ++ public CompletableFuture> getChunkAtAsynchronously(int x, int z, boolean gen, boolean isUrgent) { + if (Thread.currentThread() != this.serverThread) { ++ CompletableFuture> future = new CompletableFuture>(); + this.serverThreadQueue.execute(() -> { -+ this.getChunkAtAsynchronously(x, z, gen, onComplete); ++ this.getChunkAtAsynchronously(x, z, gen, isUrgent).whenComplete((chunk, ex) -> { ++ if (ex != null) { ++ future.completeExceptionally(ex); ++ } else { ++ future.complete(chunk); ++ } ++ }); + }); -+ return; ++ return future; ++ } ++ ++ if (!com.destroystokyo.paper.PaperConfig.asyncChunks) { ++ return CompletableFuture.completedFuture(Either.left(getChunkAt(x, z, gen))); + } + + long k = ChunkCoordIntPair.pair(x, z); @@ -2346,75 +2357,64 @@ index 4c9c8e483974f8869d6711626620cfd7d814d956..259af7095c453e52e7c3a8662968d96d + this.cacheStatus[0] = ChunkStatus.FULL; + this.cacheChunk[0] = ichunkaccess; + -+ onComplete.accept((Chunk)ichunkaccess); -+ -+ return; ++ return CompletableFuture.completedFuture(Either.left(ichunkaccess)); + } + } + } + + if (gen) { -+ this.bringToFullStatusAsync(x, z, chunkPos, onComplete); -+ return; ++ return this.bringToFullStatusAsync(x, z, chunkPos, isUrgent); + } + + IChunkAccess current = this.getChunkAtImmediately(x, z); // we want to bypass ticket restrictions + if (current != null) { + if (!(current instanceof ProtoChunkExtension) && !(current instanceof net.minecraft.server.Chunk)) { -+ onComplete.accept(null); // the chunk is not gen'd -+ return; ++ return CompletableFuture.completedFuture(Either.left(null)); + } + // we know the chunk is at full status here (either in read-only mode or the real thing) -+ this.bringToFullStatusAsync(x, z, chunkPos, onComplete); -+ return; ++ return this.bringToFullStatusAsync(x, z, chunkPos, isUrgent); + } + + ChunkStatus status = world.getChunkProvider().playerChunkMap.getStatusOnDiskNoLoad(x, z); + + if (status != null && status != ChunkStatus.FULL) { + // does not exist on disk -+ onComplete.accept(null); -+ return; ++ return CompletableFuture.completedFuture(Either.left(null)); + } + + if (status == ChunkStatus.FULL) { -+ this.bringToFullStatusAsync(x, z, chunkPos, onComplete); -+ return; ++ return this.bringToFullStatusAsync(x, z, chunkPos, isUrgent); + } + + // status is null here + + // here we don't know what status it is and we're not supposed to generate + // so we asynchronously load empty status -+ -+ this.bringToStatusAsync(x, z, chunkPos, ChunkStatus.EMPTY, (IChunkAccess chunk) -> { -+ if (!(chunk instanceof ProtoChunkExtension) && !(chunk instanceof net.minecraft.server.Chunk)) { ++ return this.bringToStatusAsync(x, z, chunkPos, ChunkStatus.EMPTY, isUrgent).thenCompose((either) -> { ++ IChunkAccess chunk = either.left().orElse(null); ++ if (!(chunk instanceof ProtoChunkExtension) && !(chunk instanceof Chunk)) { + // the chunk on disk was not a full status chunk -+ onComplete.accept(null); -+ return; ++ return CompletableFuture.completedFuture(Either.left(null)); + } -+ this.bringToFullStatusAsync(x, z, chunkPos, onComplete); // bring to full status if required ++ ; // bring to full status if required ++ return this.bringToFullStatusAsync(x, z, chunkPos, isUrgent); + }); + } + -+ private void bringToFullStatusAsync(int x, int z, ChunkCoordIntPair chunkPos, java.util.function.Consumer onComplete) { -+ this.bringToStatusAsync(x, z, chunkPos, ChunkStatus.FULL, (java.util.function.Consumer)onComplete); ++ private CompletableFuture> bringToFullStatusAsync(int x, int z, ChunkCoordIntPair chunkPos, boolean isUrgent) { ++ return this.bringToStatusAsync(x, z, chunkPos, ChunkStatus.FULL, isUrgent); + } + -+ private void bringToStatusAsync(int x, int z, ChunkCoordIntPair chunkPos, ChunkStatus status, java.util.function.Consumer onComplete) { ++ private CompletableFuture> bringToStatusAsync(int x, int z, ChunkCoordIntPair chunkPos, ChunkStatus status, boolean isUrgent) { + CompletableFuture> future = this.getChunkFutureMainThread(x, z, status, true); + Long identifier = Long.valueOf(this.asyncLoadSeqCounter++); + int ticketLevel = MCUtil.getTicketLevelFor(status); + this.addTicketAtLevel(TicketType.ASYNC_LOAD, chunkPos, ticketLevel, identifier); + -+ future.whenCompleteAsync((Either either, Throwable throwable) -> { ++ return future.thenComposeAsync((Either either) -> { + // either left -> success + // either right -> failure + -+ if (throwable != null) { -+ throw new RuntimeException(throwable); -+ } -+ + this.removeTicketAtLevel(TicketType.ASYNC_LOAD, chunkPos, ticketLevel, identifier); + this.addTicketAtLevel(TicketType.UNKNOWN, chunkPos, ticketLevel, chunkPos); // allow unloading + @@ -2425,8 +2425,7 @@ index 4c9c8e483974f8869d6711626620cfd7d814d956..259af7095c453e52e7c3a8662968d96d + throw new IllegalStateException("Chunk failed to load: " + failure.get().toString()); + } + -+ onComplete.accept(either.left().get()); -+ ++ return CompletableFuture.completedFuture(either); + }, this.serverThreadQueue); + } + @@ -2446,7 +2445,7 @@ index 4c9c8e483974f8869d6711626620cfd7d814d956..259af7095c453e52e7c3a8662968d96d if (Thread.currentThread() != this.serverThread) { return (IChunkAccess) CompletableFuture.supplyAsync(() -> { return this.getChunkAt(i, j, chunkstatus, flag); -@@ -329,8 +455,13 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -329,8 +454,13 @@ public class ChunkProviderServer extends IChunkProvider { CompletableFuture> completablefuture = this.getChunkFutureMainThread(i, j, chunkstatus, flag); if (!completablefuture.isDone()) { // Paper @@ -2460,7 +2459,7 @@ index 4c9c8e483974f8869d6711626620cfd7d814d956..259af7095c453e52e7c3a8662968d96d this.world.timings.syncChunkLoad.stopTiming(); // Paper } // Paper ichunkaccess = (IChunkAccess) ((Either) completablefuture.join()).map((ichunkaccess1) -> { -@@ -835,11 +966,12 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -835,11 +965,12 @@ public class ChunkProviderServer extends IChunkProvider { protected boolean executeNext() { // CraftBukkit start - process pending Chunk loadCallback() and unloadCallback() after each run task try { @@ -3923,7 +3922,7 @@ index c999f8c9bf8a59e19b3d6d1b7ad8b5fb6e48b928..b59ef1a63338aa150d39e8014e12b227 HAS_SPACE(VillagePlaceRecord::d), IS_OCCUPIED(VillagePlaceRecord::e), ANY((villageplacerecord) -> { diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java -index 8561f96b9a10cc2faa3ec1087a05ddb4c6164938..c0476f69e4a3f079f9160a4d5d384556597ec279 100644 +index 8561f96b9a10cc2faa3ec1087a05ddb4c6164938..30dbf95a02bd8e68471400245b46189f8e0560cc 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -82,6 +82,79 @@ public class WorldServer extends World { @@ -4015,24 +4014,31 @@ index 8561f96b9a10cc2faa3ec1087a05ddb4c6164938..c0476f69e4a3f079f9160a4d5d384556 } // CraftBukkit start -@@ -1673,7 +1748,11 @@ public class WorldServer extends World { +@@ -1673,7 +1748,10 @@ public class WorldServer extends World { } MCUtil.getSpiralOutChunks(spawn, radiusInBlocks >> 4).forEach(pair -> { - getChunkProvider().getChunkAtMainThread(pair.x, pair.z); -+ if (com.destroystokyo.paper.PaperConfig.asyncChunks) { -+ getChunkProvider().getChunkAtAsynchronously(pair.x, pair.z, true, (c) -> {}); -+ } else { -+ getChunkProvider().getChunkAtMainThread(pair.x, pair.z); -+ } ++ getChunkProvider().getChunkAtAsynchronously(pair.x, pair.z, true, false).exceptionally((ex) -> { ++ ex.printStackTrace(); ++ return null; ++ }); }); } public void removeTicketsForSpawn(int radiusInBlocks, BlockPosition spawn) { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 50467656df0b54c2dcba8696b5677a2fc975b178..d3ac0ffe4682e56b7654611f32beefb6bc779823 100644 +index 50467656df0b54c2dcba8696b5677a2fc975b178..711bb5c5f4a37357007e8c6441b61c474952ba4d 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -556,22 +556,23 @@ public class CraftWorld implements World { +@@ -75,6 +75,7 @@ import net.minecraft.server.GroupDataEntity; + import net.minecraft.server.IBlockData; + import net.minecraft.server.IChunkAccess; + import net.minecraft.server.MinecraftKey; ++import net.minecraft.server.MinecraftServer; + import net.minecraft.server.MovingObjectPosition; + import net.minecraft.server.PacketPlayOutCustomSoundEffect; + import net.minecraft.server.PacketPlayOutUpdateTime; +@@ -556,22 +557,23 @@ public class CraftWorld implements World { return true; } @@ -4064,26 +4070,24 @@ index 50467656df0b54c2dcba8696b5677a2fc975b178..d3ac0ffe4682e56b7654611f32beefb6 // fall through to load // we do this so we do not re-read the chunk data on disk -@@ -2443,6 +2444,24 @@ public class CraftWorld implements World { +@@ -2443,6 +2445,22 @@ public class CraftWorld implements World { return new CraftDragonBattle(((WorldProviderTheEnd) worldProvider).o()); // PAIL rename getDragonBattle } + // Paper start + @Override -+ public CompletableFuture getChunkAtAsync(int x, int z, boolean gen) { ++ public CompletableFuture getChunkAtAsync(int x, int z, boolean gen, boolean urgent) { + if (Bukkit.isPrimaryThread()) { + net.minecraft.server.Chunk immediate = this.world.getChunkProvider().getChunkAtIfLoadedImmediately(x, z); + if (immediate != null) { -+ return CompletableFuture.completedFuture(immediate.bukkitChunk); ++ return CompletableFuture.completedFuture(immediate.getBukkitChunk()); + } + } + -+ CompletableFuture ret = new CompletableFuture<>(); -+ this.world.getChunkProvider().getChunkAtAsynchronously(x, z, gen, (net.minecraft.server.Chunk chunk) -> { -+ ret.complete(chunk == null ? null : chunk.bukkitChunk); -+ }); -+ -+ return ret; ++ return this.world.getChunkProvider().getChunkAtAsynchronously(x, z, gen, urgent).thenComposeAsync((either) -> { ++ net.minecraft.server.Chunk chunk = (net.minecraft.server.Chunk) either.left().orElse(null); ++ return CompletableFuture.completedFuture(chunk == null ? null : chunk.getBukkitChunk()); ++ }, MinecraftServer.getServer()); + } + // Paper end diff --git a/Spigot-Server-Patches/0392-Reduce-sync-loads.patch b/Spigot-Server-Patches/0392-Reduce-sync-loads.patch index 8da5cfc0f..61c27ff91 100644 --- a/Spigot-Server-Patches/0392-Reduce-sync-loads.patch +++ b/Spigot-Server-Patches/0392-Reduce-sync-loads.patch @@ -285,10 +285,10 @@ index 0000000000000000000000000000000000000000..59aec103295f747793fdc0a52eb45f41 + } +} diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index 259af7095c453e52e7c3a8662968d96de0efbbc8..ea1117dc86e9621c37ab4ba0f7c42e7b172648b3 100644 +index cabe2a5908dd9ee721c13c1825e65a37f72361d4..61640d814426732a03d8bb3394c2cd3414a27a6c 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java -@@ -459,6 +459,7 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -458,6 +458,7 @@ public class ChunkProviderServer extends IChunkProvider { this.world.asyncChunkTaskManager.raisePriority(x, z, com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY); com.destroystokyo.paper.io.chunk.ChunkTaskManager.pushChunkWait(this.world, x, z); // Paper end @@ -328,7 +328,7 @@ index 311685180fe720706dfb6c82b1b54f9876187b73..568e04faa314552e14286efdfcdfb79e if (chunk != null) { chunk.a(oclass, axisalignedbb, list, predicate); diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java -index c0476f69e4a3f079f9160a4d5d384556597ec279..2fa1b86adf89bb9b2398806bf30b0a6e436a4577 100644 +index 30dbf95a02bd8e68471400245b46189f8e0560cc..4fea35783caa4d93de83e256b565f0e80212e9a5 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -154,6 +154,12 @@ public class WorldServer extends World { diff --git a/Spigot-Server-Patches/0396-implement-optional-per-player-mob-spawns.patch b/Spigot-Server-Patches/0396-implement-optional-per-player-mob-spawns.patch index 51468e357..a4aef1fd1 100644 --- a/Spigot-Server-Patches/0396-implement-optional-per-player-mob-spawns.patch +++ b/Spigot-Server-Patches/0396-implement-optional-per-player-mob-spawns.patch @@ -545,10 +545,10 @@ index 0000000000000000000000000000000000000000..4f13d3ff8391793a99f067189f854078 + } +} diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index ea1117dc86e9621c37ab4ba0f7c42e7b172648b3..fe894a68bc28ed01819bb538079856712f813713 100644 +index 61640d814426732a03d8bb3394c2cd3414a27a6c..cbaf14b24b3d941f0912788c87c3eab5aad7f5f0 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java -@@ -741,7 +741,22 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -740,7 +740,22 @@ public class ChunkProviderServer extends IChunkProvider { this.world.timings.countNaturalMobs.startTiming(); // Paper - timings int l = this.chunkMapDistance.b(); EnumCreatureType[] aenumcreaturetype = EnumCreatureType.values(); @@ -572,7 +572,7 @@ index ea1117dc86e9621c37ab4ba0f7c42e7b172648b3..fe894a68bc28ed01819bb53807985671 this.world.timings.countNaturalMobs.stopTiming(); // Paper - timings this.world.getMethodProfiler().exit(); -@@ -809,8 +824,23 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -808,8 +823,23 @@ public class ChunkProviderServer extends IChunkProvider { if (enumcreaturetype != EnumCreatureType.MISC && (!enumcreaturetype.c() || this.allowAnimals) && (enumcreaturetype.c() || this.allowMonsters) && (!enumcreaturetype.d() || flag2)) { int k1 = limit * l / ChunkProviderServer.b; // CraftBukkit - use per-world limits @@ -755,7 +755,7 @@ index fdac5bb3a2d4a73035e1d914979b87fc224b6b20..58bbf2f9d2ec91715051d40e108e1606 @Nullable diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java -index 731f6a83200b4f7608fe1f1f3f0e04d827913e72..38c5b721bf145c0083cf560763f1c6327210aebf 100644 +index e7747396c19c432de59213a440ba0dd692daadae..95c3ee7387977efe87f2c7eba017489823ba1390 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -1028,7 +1028,20 @@ public class WorldServer extends World { diff --git a/Spigot-Server-Patches/0404-Fix-spawning-of-hanging-entities-that-are-not-ItemFr.patch b/Spigot-Server-Patches/0404-Fix-spawning-of-hanging-entities-that-are-not-ItemFr.patch index 25b6b7538..b3dd514bc 100644 --- a/Spigot-Server-Patches/0404-Fix-spawning-of-hanging-entities-that-are-not-ItemFr.patch +++ b/Spigot-Server-Patches/0404-Fix-spawning-of-hanging-entities-that-are-not-ItemFr.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Fix spawning of hanging entities that are not ItemFrames and diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index d3ac0ffe4682e56b7654611f32beefb6bc779823..07ebd78acc7498616887f90a82300b4d5b71fab1 100644 +index 9a383d7d606f914de896ea07af0fea579ad5682b..8a1aca1990ca801c86065439bdd4d4a987ee3250 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -1850,7 +1850,12 @@ public class CraftWorld implements World { +@@ -1851,7 +1851,12 @@ public class CraftWorld implements World { height = 9; } diff --git a/Spigot-Server-Patches/0431-Optimise-getChunkAt-calls-for-loaded-chunks.patch b/Spigot-Server-Patches/0431-Optimise-getChunkAt-calls-for-loaded-chunks.patch index 1f97d6f40..62dd00bf9 100644 --- a/Spigot-Server-Patches/0431-Optimise-getChunkAt-calls-for-loaded-chunks.patch +++ b/Spigot-Server-Patches/0431-Optimise-getChunkAt-calls-for-loaded-chunks.patch @@ -7,10 +7,10 @@ bypass the need to get a player chunk, then get the either, then unwrap it... diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index fe894a68bc28ed01819bb538079856712f813713..e67e00653575c3e57fe16980d2ff074d8413a95e 100644 +index cbaf14b24b3d941f0912788c87c3eab5aad7f5f0..ea85f40f4d40f687f3feaf161d2248f2bcc39af2 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java -@@ -435,6 +435,12 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -434,6 +434,12 @@ public class ChunkProviderServer extends IChunkProvider { return this.getChunkAt(i, j, chunkstatus, flag); }, this.serverThreadQueue).join(); } else { @@ -23,7 +23,7 @@ index fe894a68bc28ed01819bb538079856712f813713..e67e00653575c3e57fe16980d2ff074d GameProfilerFiller gameprofilerfiller = this.world.getMethodProfiler(); gameprofilerfiller.c("getChunk"); -@@ -485,39 +491,7 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -484,39 +490,7 @@ public class ChunkProviderServer extends IChunkProvider { if (Thread.currentThread() != this.serverThread) { return null; } else { diff --git a/Spigot-Server-Patches/0456-Optimize-PlayerChunkMap-memory-use-for-visibleChunks.patch b/Spigot-Server-Patches/0456-Optimize-PlayerChunkMap-memory-use-for-visibleChunks.patch index b4d7c74e3..a26715bc1 100644 --- a/Spigot-Server-Patches/0456-Optimize-PlayerChunkMap-memory-use-for-visibleChunks.patch +++ b/Spigot-Server-Patches/0456-Optimize-PlayerChunkMap-memory-use-for-visibleChunks.patch @@ -50,10 +50,10 @@ index 0000000000000000000000000000000000000000..e0ad725b2e63ffd329fc4725d15290cb + } +} diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index ca1b5b3b094b847f96742d8466fc42c5bdedbff5..c457e3b772ec9a77dc5028853512b7e50853315d 100644 +index b4cf530bdf1027ef27a1aec40ac4fade8d8275de..e03e6465655e209563eed2313502786fa2361024 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java -@@ -750,7 +750,7 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -749,7 +749,7 @@ public class ChunkProviderServer extends IChunkProvider { entityPlayer.playerNaturallySpawnedEvent.callEvent(); }; // Paper end @@ -213,7 +213,7 @@ index 4beae504c875767ff00e26461fe7240498750e27..00f26ae23da65453073fc06ffec8a349 while (objectbidirectionaliterator.hasNext()) { Entry entry = (Entry) objectbidirectionaliterator.next(); diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index 07ebd78acc7498616887f90a82300b4d5b71fab1..b70c0fd977ce71cc8cb484249cb234dc86b59f1f 100644 +index 5e84bbad1ba75cb2b541a29d38d3f96832cff853..2393c8715603478142a1980a9a769de58f8bb3c4 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -74,6 +74,7 @@ import net.minecraft.server.GameRules; @@ -222,9 +222,9 @@ index 07ebd78acc7498616887f90a82300b4d5b71fab1..b70c0fd977ce71cc8cb484249cb234dc import net.minecraft.server.IChunkAccess; +import net.minecraft.server.MCUtil; import net.minecraft.server.MinecraftKey; + import net.minecraft.server.MinecraftServer; import net.minecraft.server.MovingObjectPosition; - import net.minecraft.server.PacketPlayOutCustomSoundEffect; -@@ -290,6 +291,7 @@ public class CraftWorld implements World { +@@ -291,6 +292,7 @@ public class CraftWorld implements World { return ret; } public int getTileEntityCount() { @@ -232,7 +232,7 @@ index 07ebd78acc7498616887f90a82300b4d5b71fab1..b70c0fd977ce71cc8cb484249cb234dc // We don't use the full world tile entity list, so we must iterate chunks Long2ObjectLinkedOpenHashMap chunks = world.getChunkProvider().playerChunkMap.visibleChunks; int size = 0; -@@ -301,11 +303,13 @@ public class CraftWorld implements World { +@@ -302,11 +304,13 @@ public class CraftWorld implements World { size += chunk.tileEntities.size(); } return size; @@ -246,7 +246,7 @@ index 07ebd78acc7498616887f90a82300b4d5b71fab1..b70c0fd977ce71cc8cb484249cb234dc int ret = 0; for (PlayerChunk chunkHolder : world.getChunkProvider().playerChunkMap.visibleChunks.values()) { -@@ -314,7 +318,7 @@ public class CraftWorld implements World { +@@ -315,7 +319,7 @@ public class CraftWorld implements World { } } @@ -255,7 +255,7 @@ index 07ebd78acc7498616887f90a82300b4d5b71fab1..b70c0fd977ce71cc8cb484249cb234dc } public int getPlayerCount() { return world.players.size(); -@@ -434,6 +438,14 @@ public class CraftWorld implements World { +@@ -435,6 +439,14 @@ public class CraftWorld implements World { @Override public Chunk[] getLoadedChunks() { diff --git a/Spigot-Server-Patches/0457-Don-t-load-chunks-when-attempting-to-unload-a-chunk.patch b/Spigot-Server-Patches/0457-Don-t-load-chunks-when-attempting-to-unload-a-chunk.patch index 57c4c44d1..b9fe78219 100644 --- a/Spigot-Server-Patches/0457-Don-t-load-chunks-when-attempting-to-unload-a-chunk.patch +++ b/Spigot-Server-Patches/0457-Don-t-load-chunks-when-attempting-to-unload-a-chunk.patch @@ -6,10 +6,10 @@ Subject: [PATCH] Don't load chunks when attempting to unload a chunk Big Brain Logic diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index b70c0fd977ce71cc8cb484249cb234dc86b59f1f..eb7b48422e06d25974f19a582c31fecb3b80271c 100644 +index e0e1f88bd4555c721f6faa9e39d1cb9e2680e969..3f70d99af9ed63d704cd58c1614b092b17f69408 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -473,7 +473,7 @@ public class CraftWorld implements World { +@@ -474,7 +474,7 @@ public class CraftWorld implements World { @Override public boolean unloadChunkRequest(int x, int z) { org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot @@ -18,7 +18,7 @@ index b70c0fd977ce71cc8cb484249cb234dc86b59f1f..eb7b48422e06d25974f19a582c31fecb if (chunk != null) { world.getChunkProvider().removeTicket(TicketType.PLUGIN, chunk.getPos(), 1, Unit.INSTANCE); } -@@ -483,7 +483,7 @@ public class CraftWorld implements World { +@@ -484,7 +484,7 @@ public class CraftWorld implements World { private boolean unloadChunk0(int x, int z, boolean save) { org.spigotmc.AsyncCatcher.catchOp("chunk unload"); // Spigot diff --git a/Spigot-Server-Patches/0459-Mid-Tick-Chunk-Tasks-Speed-up-processing-of-chunk-lo.patch b/Spigot-Server-Patches/0459-Mid-Tick-Chunk-Tasks-Speed-up-processing-of-chunk-lo.patch index c80faa0f2..1032ebca7 100644 --- a/Spigot-Server-Patches/0459-Mid-Tick-Chunk-Tasks-Speed-up-processing-of-chunk-lo.patch +++ b/Spigot-Server-Patches/0459-Mid-Tick-Chunk-Tasks-Speed-up-processing-of-chunk-lo.patch @@ -56,10 +56,10 @@ index 647f6fc8efb350fbd0bc4c40358a998f8b89b96a..9f1662ece533f5ea744662b718e2d89a + } } diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index c457e3b772ec9a77dc5028853512b7e50853315d..747305619b5050e7dad3ae0ccd62200ee2246b5a 100644 +index e03e6465655e209563eed2313502786fa2361024..21cf5ac6c38968c45bdd0f09f60743ad216cd925 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java -@@ -683,6 +683,7 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -682,6 +682,7 @@ public class ChunkProviderServer extends IChunkProvider { this.world.getMethodProfiler().enter("purge"); this.world.timings.doChunkMap.startTiming(); // Spigot this.chunkMapDistance.purgeTickets(); @@ -67,7 +67,7 @@ index c457e3b772ec9a77dc5028853512b7e50853315d..747305619b5050e7dad3ae0ccd62200e this.tickDistanceManager(); this.world.timings.doChunkMap.stopTiming(); // Spigot this.world.getMethodProfiler().exitEnter("chunks"); -@@ -692,6 +693,7 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -691,6 +692,7 @@ public class ChunkProviderServer extends IChunkProvider { this.world.timings.doChunkUnload.startTiming(); // Spigot this.world.getMethodProfiler().exitEnter("unload"); this.playerChunkMap.unloadChunks(booleansupplier); @@ -75,7 +75,7 @@ index c457e3b772ec9a77dc5028853512b7e50853315d..747305619b5050e7dad3ae0ccd62200e this.world.timings.doChunkUnload.stopTiming(); // Spigot this.world.getMethodProfiler().exit(); this.clearCache(); -@@ -750,7 +752,7 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -749,7 +751,7 @@ public class ChunkProviderServer extends IChunkProvider { entityPlayer.playerNaturallySpawnedEvent.callEvent(); }; // Paper end @@ -84,7 +84,7 @@ index c457e3b772ec9a77dc5028853512b7e50853315d..747305619b5050e7dad3ae0ccd62200e Optional optional = ((Either) playerchunk.b().getNow(PlayerChunk.UNLOADED_CHUNK)).left(); if (optional.isPresent()) { -@@ -833,6 +835,7 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -832,6 +834,7 @@ public class ChunkProviderServer extends IChunkProvider { this.world.timings.chunkTicks.startTiming(); // Spigot // Paper this.world.a(chunk, k); this.world.timings.chunkTicks.stopTiming(); // Spigot // Paper @@ -92,7 +92,7 @@ index c457e3b772ec9a77dc5028853512b7e50853315d..747305619b5050e7dad3ae0ccd62200e } } }); -@@ -974,6 +977,41 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -973,6 +976,41 @@ public class ChunkProviderServer extends IChunkProvider { super.executeTask(runnable); } @@ -226,7 +226,7 @@ index 77adc64e30cbc1d4542eb8f4a446788c1fdc61be..3c25436f158316d2e09cbf4673365edd // Spigot Start CrashReport crashreport; diff --git a/src/main/java/net/minecraft/server/WorldServer.java b/src/main/java/net/minecraft/server/WorldServer.java -index 2a7a47c6707c349af55ccd70eb3b8c48387c391a..9b5f24c262edb82a424385f8f3cb6aa506c0dcd9 100644 +index e37900348d57ff7253224238d9f9975626db9fa0..2676093bf1084ff2b905759aa09e1f1f22fd5660 100644 --- a/src/main/java/net/minecraft/server/WorldServer.java +++ b/src/main/java/net/minecraft/server/WorldServer.java @@ -432,6 +432,7 @@ public class WorldServer extends World { diff --git a/Spigot-Server-Patches/0463-Implement-Chunk-Priority-Urgency-System-for-World-Ge.patch b/Spigot-Server-Patches/0463-Implement-Chunk-Priority-Urgency-System-for-World-Ge.patch index 57bf9bc86..52d27f8ef 100644 --- a/Spigot-Server-Patches/0463-Implement-Chunk-Priority-Urgency-System-for-World-Ge.patch +++ b/Spigot-Server-Patches/0463-Implement-Chunk-Priority-Urgency-System-for-World-Ge.patch @@ -16,26 +16,15 @@ lots of chunks already. This massively reduces the lag spikes from sync chunk gens. diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index 747305619b5050e7dad3ae0ccd62200ee2246b5a..746b5b55896eaf39edf92073f61796d7096c48c2 100644 +index 21cf5ac6c38968c45bdd0f09f60743ad216cd925..fb315503b0aad2cb52cb70b5b033d33fcecd1d22 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java -@@ -308,6 +308,7 @@ public class ChunkProviderServer extends IChunkProvider { - } - - private long asyncLoadSeqCounter; -+ public static boolean IS_CHUNK_LOAD_BLOCKING_MAIN = false; - - public void getChunkAtAsynchronously(int x, int z, boolean gen, java.util.function.Consumer onComplete) { - if (Thread.currentThread() != this.serverThread) { -@@ -465,10 +466,18 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -464,10 +464,14 @@ public class ChunkProviderServer extends IChunkProvider { } gameprofilerfiller.c("getChunkCacheMiss"); -+ // Paper start - Chunk Load/Gen Priority -+ boolean prevBlocking = IS_CHUNK_LOAD_BLOCKING_MAIN; -+ IS_CHUNK_LOAD_BLOCKING_MAIN = true; -+ // Paper end - CompletableFuture> completablefuture = this.getChunkFutureMainThread(i, j, chunkstatus, flag); +- CompletableFuture> completablefuture = this.getChunkFutureMainThread(i, j, chunkstatus, flag); ++ CompletableFuture> completablefuture = this.getChunkFutureMainThread(i, j, chunkstatus, flag, true); // Paper if (!completablefuture.isDone()) { // Paper // Paper start - async chunk io/loading @@ -46,7 +35,7 @@ index 747305619b5050e7dad3ae0ccd62200ee2246b5a..746b5b55896eaf39edf92073f61796d7 this.world.asyncChunkTaskManager.raisePriority(x, z, com.destroystokyo.paper.io.PrioritizedTaskQueue.HIGHEST_PRIORITY); com.destroystokyo.paper.io.chunk.ChunkTaskManager.pushChunkWait(this.world, x, z); // Paper end -@@ -478,6 +487,11 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -477,6 +481,10 @@ public class ChunkProviderServer extends IChunkProvider { com.destroystokyo.paper.io.chunk.ChunkTaskManager.popChunkWait(); // Paper - async chunk debug this.world.timings.syncChunkLoad.stopTiming(); // Paper } // Paper @@ -54,12 +43,35 @@ index 747305619b5050e7dad3ae0ccd62200ee2246b5a..746b5b55896eaf39edf92073f61796d7 + if (playerChunk != null) { + playerChunk.clearChunkUrgent(); + } -+ IS_CHUNK_LOAD_BLOCKING_MAIN = prevBlocking;// Paper ichunkaccess = (IChunkAccess) ((Either) completablefuture.join()).map((ichunkaccess1) -> { return ichunkaccess1; }, (playerchunk_failure) -> { +@@ -508,6 +516,11 @@ public class ChunkProviderServer extends IChunkProvider { + } + + private CompletableFuture> getChunkFutureMainThread(int i, int j, ChunkStatus chunkstatus, boolean flag) { ++ // Paper start ++ return getChunkFutureMainThread(i, j, chunkstatus, flag, false); ++ } ++ private CompletableFuture> getChunkFutureMainThread(int i, int j, ChunkStatus chunkstatus, boolean flag, boolean isUrgent) { ++ // Paper end + ChunkCoordIntPair chunkcoordintpair = new ChunkCoordIntPair(i, j); + long k = chunkcoordintpair.pair(); + int l = 33 + ChunkStatus.a(chunkstatus); +@@ -535,6 +548,11 @@ public class ChunkProviderServer extends IChunkProvider { + } + } + } ++ // Paper start ++ if (playerchunk != null && isUrgent) { ++ playerchunk.markChunkUrgent(chunkstatus); ++ } ++ // Paper end + + return this.a(playerchunk, l) ? PlayerChunk.UNLOADED_CHUNK_ACCESS_FUTURE : playerchunk.a(chunkstatus, this.playerChunkMap); + } diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java -index 3d610e41969768da0d2848fa1ae195035ccfd660..4b341c81fc97076a69aede729008c54674fa7adf 100644 +index 3d610e41969768da0d2848fa1ae195035ccfd660..a6e7bcf79df9f4ad5b0a779f3eecf85f121bedc8 100644 --- a/src/main/java/net/minecraft/server/PlayerChunk.java +++ b/src/main/java/net/minecraft/server/PlayerChunk.java @@ -43,6 +43,111 @@ public class PlayerChunk { @@ -196,6 +208,14 @@ index 3d610e41969768da0d2848fa1ae195035ccfd660..4b341c81fc97076a69aede729008c546 } private void d(int i) { +@@ -441,6 +552,7 @@ public class PlayerChunk { + Chunk fullChunk = either.left().get(); + PlayerChunk.this.isFullChunkReady = true; + fullChunk.playerChunk = PlayerChunk.this; ++ this.clearChunkUrgent(); + + + } diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java index 00f26ae23da65453073fc06ffec8a349ef28dd7e..6c178492b75134ba25b7730273bb550b693a7e4a 100644 --- a/src/main/java/net/minecraft/server/PlayerChunkMap.java @@ -279,3 +299,31 @@ index 00f26ae23da65453073fc06ffec8a349ef28dd7e..6c178492b75134ba25b7730273bb550b CompletableFuture> completablefuture1 = completablefuture.thenApplyAsync((either) -> { return either.flatMap((list) -> { Chunk chunk = (Chunk) list.get(list.size() / 2); +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index b184f8ed8ce86965c3ef9aef179126a4d69275e8..64c643aa15d6ea68f9dad3104cc41e412255cee3 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -1,5 +1,6 @@ + package org.bukkit.craftbukkit; + ++import com.destroystokyo.paper.io.PrioritizedTaskQueue; + import com.google.common.base.Preconditions; + import com.google.common.collect.ImmutableList; + import com.google.common.collect.ImmutableMap; +@@ -2472,10 +2473,15 @@ public class CraftWorld implements World { + } + } + +- return this.world.getChunkProvider().getChunkAtAsynchronously(x, z, gen, urgent).thenComposeAsync((either) -> { ++ CompletableFuture future = this.world.getChunkProvider().getChunkAtAsynchronously(x, z, gen, urgent).thenComposeAsync((either) -> { + net.minecraft.server.Chunk chunk = (net.minecraft.server.Chunk) either.left().orElse(null); + return CompletableFuture.completedFuture(chunk == null ? null : chunk.getBukkitChunk()); + }, MinecraftServer.getServer()); ++ if (urgent) { ++ world.asyncChunkTaskManager.raisePriority(x, z, PrioritizedTaskQueue.HIGHEST_PRIORITY); ++ } ++ return future; ++ + } + // Paper end + diff --git a/Spigot-Server-Patches/0465-Delay-unsafe-actions-until-after-entity-ticking-is-d.patch b/Spigot-Server-Patches/0465-Delay-unsafe-actions-until-after-entity-ticking-is-d.patch index 40db4c52b..c8dd5fa06 100644 --- a/Spigot-Server-Patches/0465-Delay-unsafe-actions-until-after-entity-ticking-is-d.patch +++ b/Spigot-Server-Patches/0465-Delay-unsafe-actions-until-after-entity-ticking-is-d.patch @@ -43,16 +43,3 @@ index 9b5f24c262edb82a424385f8f3cb6aa506c0dcd9..b3785775ecd8e3c13e7829f641f2c1b5 this.getMinecraftServer().midTickLoadChunks(); // Paper try (co.aikar.timings.Timing ignored = this.timings.newEntities.startTiming()) { // Paper - timings -diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index eb7b48422e06d25974f19a582c31fecb3b80271c..ac257d50dea8f42a515f19bbae12ab5680e26bb4 100644 ---- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -+++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -2473,7 +2473,7 @@ public class CraftWorld implements World { - - CompletableFuture ret = new CompletableFuture<>(); - this.world.getChunkProvider().getChunkAtAsynchronously(x, z, gen, (net.minecraft.server.Chunk chunk) -> { -- ret.complete(chunk == null ? null : chunk.bukkitChunk); -+ this.world.doIfNotEntityTicking(() -> ret.complete(chunk == null ? null : chunk.bukkitChunk)); - }); - - return ret; diff --git a/Spigot-Server-Patches/0478-Optimize-ChunkProviderServer-s-chunk-level-checking-.patch b/Spigot-Server-Patches/0478-Optimize-ChunkProviderServer-s-chunk-level-checking-.patch index 117ed8fb6..d399056cd 100644 --- a/Spigot-Server-Patches/0478-Optimize-ChunkProviderServer-s-chunk-level-checking-.patch +++ b/Spigot-Server-Patches/0478-Optimize-ChunkProviderServer-s-chunk-level-checking-.patch @@ -9,10 +9,10 @@ so inline where possible, and avoid the abstraction of the Either class. diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index 746b5b55896eaf39edf92073f61796d7096c48c2..c2e4e4f6f1895850bcac3552eee5bfedfb98c933 100644 +index fb315503b0aad2cb52cb70b5b033d33fcecd1d22..edf0cf3680e5d2212f35c9d4464b22e0f3e87342 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java -@@ -615,27 +615,37 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -618,27 +618,37 @@ public class ChunkProviderServer extends IChunkProvider { public final boolean isInEntityTickingChunk(Entity entity) { return this.a(entity); } // Paper - OBFHELPER @Override public boolean a(Entity entity) { diff --git a/Spigot-Server-Patches/0481-Fix-Chunk-Post-Processing-deadlock-risk.patch b/Spigot-Server-Patches/0481-Fix-Chunk-Post-Processing-deadlock-risk.patch index bb58a29a9..02000ab73 100644 --- a/Spigot-Server-Patches/0481-Fix-Chunk-Post-Processing-deadlock-risk.patch +++ b/Spigot-Server-Patches/0481-Fix-Chunk-Post-Processing-deadlock-risk.patch @@ -25,10 +25,10 @@ This successfully fixed a reoccurring and highly reproduceable crash for heightmaps. diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index c2e4e4f6f1895850bcac3552eee5bfedfb98c933..78a8a3cc68f21ec3ade95c13ccacafd3a3a6c4e6 100644 +index edf0cf3680e5d2212f35c9d4464b22e0f3e87342..c3528212ae1bfbdbe6910bcd775990b9b638afaf 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java -@@ -1048,6 +1048,7 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -1051,6 +1051,7 @@ public class ChunkProviderServer extends IChunkProvider { return super.executeNext() || execChunkTask; // Paper } } finally { diff --git a/Spigot-Server-Patches/0503-Optimize-isOutsideRange-to-use-distance-maps.patch b/Spigot-Server-Patches/0503-Optimize-isOutsideRange-to-use-distance-maps.patch index 0a9f29790..614314c4c 100644 --- a/Spigot-Server-Patches/0503-Optimize-isOutsideRange-to-use-distance-maps.patch +++ b/Spigot-Server-Patches/0503-Optimize-isOutsideRange-to-use-distance-maps.patch @@ -77,10 +77,10 @@ index 279c7a85fb5b4bff91fba1c9797c902bd68d8539..7cd4e2912351eae35b46dba1c8a471af public String c() { diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java -index 78a8a3cc68f21ec3ade95c13ccacafd3a3a6c4e6..e2abda1bc37b9be0bae2506f0f26360693f3d30a 100644 +index c3528212ae1bfbdbe6910bcd775990b9b638afaf..89017e002f4381ffdae1678349d674474088fb4f 100644 --- a/src/main/java/net/minecraft/server/ChunkProviderServer.java +++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java -@@ -733,6 +733,36 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -736,6 +736,36 @@ public class ChunkProviderServer extends IChunkProvider { boolean flag1 = this.world.getGameRules().getBoolean(GameRules.DO_MOB_SPAWNING) && !world.getPlayers().isEmpty(); // CraftBukkit if (!flag) { @@ -117,7 +117,7 @@ index 78a8a3cc68f21ec3ade95c13ccacafd3a3a6c4e6..e2abda1bc37b9be0bae2506f0f263606 this.world.getMethodProfiler().enter("pollingChunks"); int k = this.world.getGameRules().getInt(GameRules.RANDOM_TICK_SPEED); BlockPosition blockposition = this.world.getSpawn(); -@@ -767,15 +797,7 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -770,15 +800,7 @@ public class ChunkProviderServer extends IChunkProvider { this.world.timings.countNaturalMobs.stopTiming(); // Paper - timings this.world.getMethodProfiler().exit(); @@ -134,7 +134,7 @@ index 78a8a3cc68f21ec3ade95c13ccacafd3a3a6c4e6..e2abda1bc37b9be0bae2506f0f263606 final int[] chunksTicked = {0}; this.playerChunkMap.forEachVisibleChunk((playerchunk) -> { // Paper - safe iterator incase chunk loads, also no wrapping Optional optional = ((Either) playerchunk.b().getNow(PlayerChunk.UNLOADED_CHUNK)).left(); -@@ -789,10 +811,10 @@ public class ChunkProviderServer extends IChunkProvider { +@@ -792,10 +814,10 @@ public class ChunkProviderServer extends IChunkProvider { this.world.getMethodProfiler().exit(); ChunkCoordIntPair chunkcoordintpair = playerchunk.i(); @@ -161,7 +161,7 @@ index 48bbaec4b64bede8d280bd866436f5528578013e..6e8179b4651fca214b8957992ec6c943 super((World) worldserver, gameprofile); playerinteractmanager.player = this; diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java -index 4b341c81fc97076a69aede729008c54674fa7adf..bae9371a1e220f4fc78a3905cad24a2e7f88771c 100644 +index a6e7bcf79df9f4ad5b0a779f3eecf85f121bedc8..0f303be3c3257548d1888ddbb575ba69ba12d0b8 100644 --- a/src/main/java/net/minecraft/server/PlayerChunk.java +++ b/src/main/java/net/minecraft/server/PlayerChunk.java @@ -148,6 +148,18 @@ public class PlayerChunk { diff --git a/Spigot-Server-Patches/0505-No-Tick-view-distance-implementation.patch b/Spigot-Server-Patches/0505-No-Tick-view-distance-implementation.patch index 2e3098d94..56209181a 100644 --- a/Spigot-Server-Patches/0505-No-Tick-view-distance-implementation.patch +++ b/Spigot-Server-Patches/0505-No-Tick-view-distance-implementation.patch @@ -114,7 +114,7 @@ index 6e8179b4651fca214b8957992ec6c9438c0da799..e32c458dfe5f22572a365cbcdf45140b super((World) worldserver, gameprofile); playerinteractmanager.player = this; diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java -index bae9371a1e220f4fc78a3905cad24a2e7f88771c..9d71c4c455d68bcc82dc56b0706c7305e4897e46 100644 +index 0f303be3c3257548d1888ddbb575ba69ba12d0b8..7b2a3287ce8d296d29cbef45322a469921cf9944 100644 --- a/src/main/java/net/minecraft/server/PlayerChunk.java +++ b/src/main/java/net/minecraft/server/PlayerChunk.java @@ -160,6 +160,18 @@ public class PlayerChunk { @@ -600,10 +600,10 @@ index 899c535c4056cd2375ab8f834f03267d405f4bda..0e6368d0fb3beccb492ae3867fb4e228 if (!this.isClientSide && (i & 1) != 0) { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -index ac257d50dea8f42a515f19bbae12ab5680e26bb4..4aafad0762df44990ed9d610a59f3862bd3fe3b0 100644 +index 64c643aa15d6ea68f9dad3104cc41e412255cee3..874240d9dddc3150d65d56d95c459b59f07b8815 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java -@@ -2483,10 +2483,39 @@ public class CraftWorld implements World { +@@ -2488,10 +2488,39 @@ public class CraftWorld implements World { // Spigot start @Override public int getViewDistance() { diff --git a/Spigot-Server-Patches/0507-Fix-Light-Command.patch b/Spigot-Server-Patches/0507-Fix-Light-Command.patch index 9e1cce124..afa04c6a8 100644 --- a/Spigot-Server-Patches/0507-Fix-Light-Command.patch +++ b/Spigot-Server-Patches/0507-Fix-Light-Command.patch @@ -7,7 +7,7 @@ This lets you run /paper fixlight (max 5) to automatically fix all light data in the chunks. diff --git a/src/main/java/com/destroystokyo/paper/PaperCommand.java b/src/main/java/com/destroystokyo/paper/PaperCommand.java -index ddb60e9a48e5e7225ad575240b94fda24b6b78ca..bd9c56dd277c58b5f2c423f6e3e65a5086099619 100644 +index ddb60e9a48e5e7225ad575240b94fda24b6b78ca..beb50f78e8b2f79d45e2e7fdc932e947138be7aa 100644 --- a/src/main/java/com/destroystokyo/paper/PaperCommand.java +++ b/src/main/java/com/destroystokyo/paper/PaperCommand.java @@ -19,6 +19,7 @@ import org.bukkit.command.Command; @@ -45,7 +45,7 @@ index ddb60e9a48e5e7225ad575240b94fda24b6b78ca..bd9c56dd277c58b5f2c423f6e3e65a50 case "ver": case "version": Command ver = org.bukkit.Bukkit.getServer().getCommandMap().getCommand("version"); -@@ -156,6 +160,65 @@ public class PaperCommand extends Command { +@@ -156,6 +160,75 @@ public class PaperCommand extends Command { return true; } @@ -81,7 +81,17 @@ index ddb60e9a48e5e7225ad575240b94fda24b6b78ca..bd9c56dd277c58b5f2c423f6e3e65a50 + sender.sendMessage("All Chunks Light updated"); + return; + } -+ world.getChunkProvider().getChunkAtAsynchronously(coord.x, coord.z, false, chunk -> { ++ world.getChunkProvider().getChunkAtAsynchronously(coord.x, coord.z, false, false).whenCompleteAsync((either, ex) -> { ++ if (ex != null) { ++ sender.sendMessage("Error loading chunk " + coord); ++ updateLight(sender, world, lightengine, queue); ++ return; ++ } ++ Chunk chunk = (Chunk) either.left().orElse(null); ++ if (chunk == null) { ++ updateLight(sender, world, lightengine, queue); ++ return; ++ } + lightengine.a(world.paperConfig.lightQueueSize + 16 * 256); // ensure full chunk can fit into queue + sender.sendMessage("Updating Light " + coord); + for (int y = 0; y < world.getHeight(); y++) { @@ -105,14 +115,14 @@ index ddb60e9a48e5e7225ad575240b94fda24b6b78ca..bd9c56dd277c58b5f2c423f6e3e65a50 + updateLight(sender, world, lightengine, queue); + } + lightengine.a(world.paperConfig.lightQueueSize); -+ }); ++ }, MinecraftServer.getServer()); + } + private void doSyncLoadInfo(CommandSender sender, String[] args) { if (!SyncLoadFinder.ENABLED) { sender.sendMessage(ChatColor.RED + "This command requires the server startup flag '-Dpaper.debug-sync-loads=true' to be set."); diff --git a/src/main/java/net/minecraft/server/PlayerChunk.java b/src/main/java/net/minecraft/server/PlayerChunk.java -index 9d71c4c455d68bcc82dc56b0706c7305e4897e46..709e35cd4864eb666b68c1b6666a9d3a5a5a3c29 100644 +index 7b2a3287ce8d296d29cbef45322a469921cf9944..d0085b7459293e3e3460cfda34c67bda6e7bc324 100644 --- a/src/main/java/net/minecraft/server/PlayerChunk.java +++ b/src/main/java/net/minecraft/server/PlayerChunk.java @@ -437,6 +437,7 @@ public class PlayerChunk {