Add Urgent API for Async Chunks API and use it for Async Teleport

This also cleans up the implementation of Async Chunks to get rid of most
Consumer callbacks and instead return futures.

This lets us propogate errors correctly up the future chain
(barring one isn't lost even deeper in the chain...)

So exceptions can now bubble to plugins using getChunkAtAsync
This commit is contained in:
Aikar 2020-05-09 22:30:28 -04:00
parent ad8e59dc79
commit e5f6489602
No known key found for this signature in database
GPG Key ID: 401ADFC9891FAAFE
20 changed files with 308 additions and 147 deletions

View File

@ -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<Chunk> getChunkAtAsync(int x, int z, boolean gen);
+ public default java.util.concurrent.CompletableFuture<Chunk> 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<Chunk> 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<Chunk> 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<Chunk> 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<Chunk> 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<Chunk> getChunkAtAsyncUrgently(int x, int z) {
+ return getChunkAtAsync(x, z, true, true);
+ }
+
+ @NotNull
+ java.util.concurrent.CompletableFuture<Chunk> 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<Boolean> teleportAsync(@NotNull Location loc, @NotNull TeleportCause cause) {
+ java.util.concurrent.CompletableFuture<Boolean> 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

View File

@ -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);

View File

@ -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();

View File

@ -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

View File

@ -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 extends Entity> T spawn(@NotNull Location location, @NotNull Class<T> 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

View File

@ -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<Chunk> onComplete) {
+ public CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> getChunkAtAsynchronously(int x, int z, boolean gen, boolean isUrgent) {
+ if (Thread.currentThread() != this.serverThread) {
+ CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> future = new CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>>();
+ 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<Chunk> onComplete) {
+ this.bringToStatusAsync(x, z, chunkPos, ChunkStatus.FULL, (java.util.function.Consumer)onComplete);
+ private CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> 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<IChunkAccess> onComplete) {
+ private CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> bringToStatusAsync(int x, int z, ChunkCoordIntPair chunkPos, ChunkStatus status, boolean isUrgent) {
+ CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> 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<IChunkAccess, PlayerChunk.Failure> either, Throwable throwable) -> {
+ return future.thenComposeAsync((Either<IChunkAccess, PlayerChunk.Failure> 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<Either<IChunkAccess, PlayerChunk.Failure>> 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<Chunk> getChunkAtAsync(int x, int z, boolean gen) {
+ public CompletableFuture<Chunk> 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<Chunk> 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

View File

@ -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 {

View File

@ -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 {

View File

@ -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;
}

View File

@ -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 {

View File

@ -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<PlayerChunk> 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<PlayerChunk> 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() {

View File

@ -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

View File

@ -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<Chunk> 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 {

View File

@ -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<Chunk> 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<Either<IChunkAccess, PlayerChunk.Failure>> completablefuture = this.getChunkFutureMainThread(i, j, chunkstatus, flag);
- CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> completablefuture = this.getChunkFutureMainThread(i, j, chunkstatus, flag);
+ CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> 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<Either<IChunkAccess, PlayerChunk.Failure>> getChunkFutureMainThread(int i, int j, ChunkStatus chunkstatus, boolean flag) {
+ // Paper start
+ return getChunkFutureMainThread(i, j, chunkstatus, flag, false);
+ }
+ private CompletableFuture<Either<IChunkAccess, PlayerChunk.Failure>> 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<Either<Chunk, PlayerChunk.Failure>> 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<Chunk> 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

View File

@ -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<Chunk> 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;

View File

@ -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) {

View File

@ -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 {

View File

@ -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<Chunk> 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 {

View File

@ -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() {

View File

@ -7,7 +7,7 @@ This lets you run /paper fixlight <chunkRadius> (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 {