From fad2494af1a041aa18d2ec73cecd6ea787895ba9 Mon Sep 17 00:00:00 2001 From: Spottedleaf Date: Sat, 6 Jun 2020 19:23:46 +1000 Subject: [PATCH] #673: Fix Craftworld#isChunkLoaded The flag for getChunkAt(int, int, ChunkStatus, boolean) is actually a flag for whether to bring the underlying PlayerChunk up to the required ticket level to load the chunk. So, if the chunk is already at the required level, but has not yet loaded, the call will actually either start the load if it has not already been started and block until completion. This behaviour is not suitable for just checking if the chunk is loaded. --- nms-patches/ChunkProviderServer.patch | 33 ++++++++++++++----- .../org/bukkit/craftbukkit/CraftWorld.java | 12 +++---- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/nms-patches/ChunkProviderServer.patch b/nms-patches/ChunkProviderServer.patch index 1309bf5263..5111274053 100644 --- a/nms-patches/ChunkProviderServer.patch +++ b/nms-patches/ChunkProviderServer.patch @@ -1,6 +1,23 @@ --- a/net/minecraft/server/ChunkProviderServer.java +++ b/net/minecraft/server/ChunkProviderServer.java -@@ -95,7 +95,7 @@ +@@ -51,6 +51,16 @@ + this.clearCache(); + } + ++ // CraftBukkit start - properly implement isChunkLoaded ++ public boolean isChunkLoaded(int chunkX, int chunkZ) { ++ PlayerChunk chunk = this.playerChunkMap.getUpdatingChunk(ChunkCoordIntPair.pair(chunkX, chunkZ)); ++ if (chunk == null) { ++ return false; ++ } ++ return chunk.getFullChunk() != null; ++ } ++ // CraftBukkit end ++ + @Override + public LightEngineThreaded getLightEngine() { + return this.lightEngine; +@@ -95,7 +105,7 @@ for (int l = 0; l < 4; ++l) { if (k == this.cachePos[l] && chunkstatus == this.cacheStatus[l]) { ichunkaccess = this.cacheChunk[l]; @@ -9,7 +26,7 @@ return ichunkaccess; } } -@@ -141,12 +141,12 @@ +@@ -141,12 +151,12 @@ if (playerchunk == null) { return null; } else { @@ -24,7 +41,7 @@ if (ichunkaccess1 != null) { this.a(k, ichunkaccess1, ChunkStatus.FULL); -@@ -173,7 +173,15 @@ +@@ -173,7 +183,15 @@ int l = 33 + ChunkStatus.a(chunkstatus); PlayerChunk playerchunk = this.getChunk(k); @@ -41,7 +58,7 @@ this.chunkMapDistance.a(TicketType.UNKNOWN, chunkcoordintpair, l, chunkcoordintpair); if (this.a(playerchunk, l)) { GameProfilerFiller gameprofilerfiller = this.world.getMethodProfiler(); -@@ -192,7 +200,7 @@ +@@ -192,7 +210,7 @@ } private boolean a(@Nullable PlayerChunk playerchunk, int i) { @@ -50,7 +67,7 @@ } public boolean isLoaded(int i, int j) { -@@ -294,11 +302,31 @@ +@@ -294,11 +312,31 @@ @Override public void close() throws IOException { @@ -83,7 +100,7 @@ public void tick(BooleanSupplier booleansupplier) { this.world.getMethodProfiler().enter("purge"); this.chunkMapDistance.purgeTickets(); -@@ -318,13 +346,19 @@ +@@ -318,13 +356,19 @@ this.lastTickTime = i; WorldData worlddata = this.world.getWorldData(); boolean flag = worlddata.getType() == WorldType.DEBUG_ALL_BLOCK_STATES; @@ -105,7 +122,7 @@ this.world.getMethodProfiler().enter("naturalSpawnCount"); int l = this.chunkMapDistance.b(); -@@ -353,8 +387,35 @@ +@@ -353,8 +397,35 @@ for (int j1 = 0; j1 < i1; ++j1) { EnumCreatureType enumcreaturetype = aenumcreaturetype1[j1]; @@ -142,7 +159,7 @@ if (object2intmap.getInt(enumcreaturetype) <= k1) { SpawnerCreature.a(enumcreaturetype, this.world, chunk, blockposition); -@@ -507,12 +568,18 @@ +@@ -507,12 +578,18 @@ @Override protected boolean executeNext() { diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 5318dfd2b5..831048f83a 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -340,8 +340,7 @@ public class CraftWorld implements World { @Override public boolean isChunkLoaded(int x, int z) { - net.minecraft.server.Chunk chunk = world.getChunkProvider().getChunkAt(x, z, false); - return chunk != null; + return world.getChunkProvider().isChunkLoaded(x, z); } @Override @@ -381,19 +380,18 @@ public class CraftWorld implements World { @Override public boolean unloadChunkRequest(int x, int z) { - net.minecraft.server.IChunkAccess chunk = world.getChunkProvider().getChunkAt(x, z, ChunkStatus.FULL, false); - if (chunk != null) { - world.getChunkProvider().removeTicket(TicketType.PLUGIN, chunk.getPos(), 1, Unit.INSTANCE); + if (isChunkLoaded(x, z)) { + world.getChunkProvider().removeTicket(TicketType.PLUGIN, new ChunkCoordIntPair(x, z), 1, Unit.INSTANCE); } return true; } private boolean unloadChunk0(int x, int z, boolean save) { - net.minecraft.server.Chunk chunk = (net.minecraft.server.Chunk) world.getChunkProvider().getChunkAt(x, z, ChunkStatus.FULL, false); - if (chunk == null) { + if (!isChunkLoaded(x, z)) { return true; } + net.minecraft.server.Chunk chunk = world.getChunkAt(x, z); chunk.mustNotSave = !save; unloadChunkRequest(x, z);