diff --git a/nms-patches/Chunk.patch b/nms-patches/Chunk.patch index 3c96375521..5a5ad49b22 100644 --- a/nms-patches/Chunk.patch +++ b/nms-patches/Chunk.patch @@ -5,17 +5,18 @@ import org.apache.logging.log4j.Logger; +import com.google.common.collect.Lists; // CraftBukkit -+import org.bukkit.Bukkit; // CraftBukkit ++import org.bukkit.Server; // CraftBukkit + public class Chunk { private static final Logger e = LogManager.getLogger(); -@@ -42,6 +45,34 @@ +@@ -42,6 +45,35 @@ private ConcurrentLinkedQueue y; public boolean d; + // CraftBukkit start - Neighbor loaded cache for chunk lighting and entity ticking + private int neighbors = 0x1 << 12; ++ public long chunkKey; + + public boolean areNeighborsLoaded(final int radius) { + switch (radius) { @@ -45,12 +46,13 @@ public Chunk(World world, int i, int j) { this.sections = new ChunkSection[16]; this.g = new byte[256]; -@@ -62,8 +93,14 @@ +@@ -62,8 +94,15 @@ Arrays.fill(this.h, -999); Arrays.fill(this.g, (byte) -1); + // CraftBukkit start + this.bukkitChunk = new org.bukkit.craftbukkit.CraftChunk(this); ++ this.chunkKey = ChunkCoordIntPair.a(this.locX, this.locZ); } + public org.bukkit.Chunk bukkitChunk; @@ -60,7 +62,7 @@ public Chunk(World world, ChunkSnapshot chunksnapshot, int i, int j) { this(world, i, j); boolean flag = true; -@@ -467,7 +504,8 @@ +@@ -467,7 +506,8 @@ } } @@ -70,7 +72,7 @@ block.onPlace(this.world, blockposition, iblockdata); } -@@ -604,7 +642,15 @@ +@@ -604,7 +644,15 @@ @Nullable public TileEntity a(BlockPosition blockposition, Chunk.EnumTileEntityState chunk_enumtileentitystate) { @@ -87,7 +89,7 @@ if (tileentity == null) { if (chunk_enumtileentitystate == Chunk.EnumTileEntityState.IMMEDIATE) { -@@ -639,6 +685,13 @@ +@@ -639,6 +687,13 @@ tileentity.z(); this.tileEntities.put(blockposition, tileentity); @@ -101,7 +103,7 @@ } } -@@ -681,9 +734,21 @@ +@@ -681,9 +736,21 @@ int i = aentityslice.length; for (int j = 0; j < i; ++j) { @@ -111,21 +113,21 @@ + java.util.Iterator iter = newList.iterator(); + while (iter.hasNext()) { + Entity entity = iter.next(); - -- this.world.c((Collection) entityslice); ++ + // Do not pass along players, as doing so can get them stuck outside of time. + // (which for example disables inventory icon updates and prevents block breaking) + if (entity instanceof EntityPlayer) { + iter.remove(); + } + } -+ -+ this.world.c((Collection) newList); + +- this.world.c((Collection) entityslice); ++ this.world.c(newList); + // CraftBukkit end } } -@@ -745,8 +810,8 @@ +@@ -745,8 +812,8 @@ while (iterator.hasNext()) { Entity entity = (Entity) iterator.next(); @@ -136,7 +138,43 @@ } } } -@@ -809,6 +874,29 @@ +@@ -773,7 +840,34 @@ + return false; + } + +- public void loadNearby(IChunkProvider ichunkprovider, ChunkGenerator chunkgenerator) { ++ // CraftBukkit start ++ public void loadNearby(IChunkProvider ichunkprovider, ChunkGenerator chunkgenerator, boolean newChunk) { ++ Server server = world.getServer(); ++ if (server != null) { ++ /* ++ * If it's a new world, the first few chunks are generated inside ++ * the World constructor. We can't reliably alter that, so we have ++ * no way of creating a CraftWorld/CraftServer at that point. ++ */ ++ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(bukkitChunk, newChunk)); ++ } ++ ++ // Update neighbor counts ++ for (int x = -2; x < 3; x++) { ++ for (int z = -2; z < 3; z++) { ++ if (x == 0 && z == 0) { ++ continue; ++ } ++ ++ Chunk neighbor = getWorld().getChunkIfLoaded(locX + x, locZ + z); ++ if (neighbor != null) { ++ neighbor.setNeighborLoaded(-x, -z); ++ setNeighborLoaded(x, z); ++ } ++ } ++ } ++ // CraftBukkit end ++ + Chunk chunk = ichunkprovider.getLoadedChunkAt(this.locX, this.locZ - 1); + Chunk chunk1 = ichunkprovider.getLoadedChunkAt(this.locX + 1, this.locZ); + Chunk chunk2 = ichunkprovider.getLoadedChunkAt(this.locX, this.locZ + 1); +@@ -809,6 +903,29 @@ } else { this.o(); chunkgenerator.recreateStructures(this.locX, this.locZ); diff --git a/nms-patches/ChunkProviderServer.patch b/nms-patches/ChunkProviderServer.patch index f6fa24c829..bb34c2031b 100644 --- a/nms-patches/ChunkProviderServer.patch +++ b/nms-patches/ChunkProviderServer.patch @@ -1,11 +1,10 @@ --- a/net/minecraft/server/ChunkProviderServer.java +++ b/net/minecraft/server/ChunkProviderServer.java -@@ -14,6 +14,12 @@ +@@ -14,6 +14,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +// CraftBukkit start -+import org.bukkit.Server; +import org.bukkit.craftbukkit.chunkio.ChunkIOExecutor; +import org.bukkit.event.world.ChunkUnloadEvent; +// CraftBukkit end @@ -13,7 +12,7 @@ public class ChunkProviderServer implements IChunkProvider { private static final Logger a = LogManager.getLogger(); -@@ -69,6 +75,26 @@ +@@ -69,19 +74,82 @@ Chunk chunk = this.getLoadedChunkAt(i, j); if (chunk == null) { @@ -40,7 +39,12 @@ chunk = this.loadChunk(i, j); if (chunk != null) { this.chunks.put(ChunkCoordIntPair.a(i, j), chunk); -@@ -80,8 +106,52 @@ + chunk.addEntities(); +- chunk.loadNearby(this, this.chunkGenerator); ++ chunk.loadNearby(this, this.chunkGenerator, false); // CraftBukkit + } + } + return chunk; } @@ -89,50 +93,21 @@ + + public Chunk originalGetChunkAt(int i, int j) { + Chunk chunk = this.originalGetOrLoadChunkAt(i, j); -+ boolean newChunk = false; + // CraftBukkit end if (chunk == null) { long k = ChunkCoordIntPair.a(i, j); -@@ -97,9 +167,37 @@ - crashreportsystemdetails.a("Generator", (Object) this.chunkGenerator); - throw new ReportedException(crashreport); - } -+ newChunk = true; // CraftBukkit +@@ -100,7 +168,8 @@ this.chunks.put(k, chunk); chunk.addEntities(); +- chunk.loadNearby(this, this.chunkGenerator); + -+ // CraftBukkit start -+ Server server = world.getServer(); -+ if (server != null) { -+ /* -+ * If it's a new world, the first few chunks are generated inside -+ * the World constructor. We can't reliably alter that, so we have -+ * no way of creating a CraftWorld/CraftServer at that point. -+ */ -+ server.getPluginManager().callEvent(new org.bukkit.event.world.ChunkLoadEvent(chunk.bukkitChunk, newChunk)); -+ } -+ -+ // Update neighbor counts -+ for (int x = -2; x < 3; x++) { -+ for (int z = -2; z < 3; z++) { -+ if (x == 0 && z == 0) { -+ continue; -+ } -+ -+ Chunk neighbor = this.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z); -+ if (neighbor != null) { -+ neighbor.setNeighborLoaded(-x, -z); -+ chunk.setNeighborLoaded(x, z); -+ } -+ } -+ } -+ // CraftBukkit end - chunk.loadNearby(this, this.chunkGenerator); ++ chunk.loadNearby(this, this.chunkGenerator, true); // CraftBukkit } -@@ -146,10 +244,12 @@ + return chunk; +@@ -146,10 +215,12 @@ public boolean a(boolean flag) { int i = 0; @@ -148,33 +123,60 @@ if (flag) { this.saveChunkNOP(chunk); -@@ -182,6 +282,29 @@ +@@ -182,10 +253,12 @@ Chunk chunk = (Chunk) this.chunks.get(olong); if (chunk != null && chunk.d) { -+ // CraftBukkit start -+ ChunkUnloadEvent event = new ChunkUnloadEvent(chunk.bukkitChunk); -+ this.world.getServer().getPluginManager().callEvent(event); -+ if (event.isCancelled()) { +- chunk.removeEntities(); +- this.saveChunk(chunk); +- this.saveChunkNOP(chunk); +- this.chunks.remove(olong); ++ // CraftBukkit start - move unload logic to own method ++ if (!unloadChunk(chunk, true)) { + continue; + } -+ -+ // Update neighbor counts -+ for (int x = -2; x < 3; x++) { -+ for (int z = -2; z < 3; z++) { -+ if (x == 0 && z == 0) { -+ continue; -+ } -+ -+ Chunk neighbor = this.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z); -+ if (neighbor != null) { -+ neighbor.setNeighborUnloaded(-x, -z); -+ chunk.setNeighborUnloaded(x, z); -+ } -+ } -+ } + // CraftBukkit end + - chunk.removeEntities(); - this.saveChunk(chunk); - this.saveChunkNOP(chunk); + ++i; + } + } +@@ -197,6 +270,39 @@ + return false; + } + ++ // CraftBukkit start ++ public boolean unloadChunk(Chunk chunk, boolean save) { ++ ChunkUnloadEvent event = new ChunkUnloadEvent(chunk.bukkitChunk); ++ this.world.getServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ return false; ++ } ++ ++ // Update neighbor counts ++ for (int x = -2; x < 3; x++) { ++ for (int z = -2; z < 3; z++) { ++ if (x == 0 && z == 0) { ++ continue; ++ } ++ ++ Chunk neighbor = this.getChunkIfLoaded(chunk.locX + x, chunk.locZ + z); ++ if (neighbor != null) { ++ neighbor.setNeighborUnloaded(-x, -z); ++ chunk.setNeighborUnloaded(x, z); ++ } ++ } ++ } ++ // Moved from unloadChunks above ++ chunk.removeEntities(); ++ if (save) { ++ this.saveChunk(chunk); ++ this.saveChunkNOP(chunk); ++ } ++ this.chunks.remove(chunk.chunkKey); ++ return true; ++ } ++ // CraftBukkit end ++ + public boolean e() { + return !this.world.savingDisabled; + } diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java index 3ee0b91ecd..2fe3eae868 100644 --- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java @@ -187,47 +187,26 @@ public class CraftWorld implements World { return false; } - return unloadChunk0(x, z, save, safe); + return unloadChunk0(x, z, save); } - private boolean unloadChunk0(int x, int z, boolean save, boolean safe) { - net.minecraft.server.Chunk chunk = world.getChunkProviderServer().getChunkAt(x, z); - if (chunk.mustSave) { // If chunk had previously been queued to save, must do save to avoid loss of that data - save = true; + private boolean unloadChunk0(int x, int z, boolean save) { + net.minecraft.server.Chunk chunk = world.getChunkProviderServer().getChunkIfLoaded(x, z); + if (chunk == null) { + return true; } - chunk.removeEntities(); // Always remove entities - even if discarding, need to get them out of world table - - if (save) { - world.getChunkProviderServer().saveChunk(chunk); - world.getChunkProviderServer().saveChunkNOP(chunk); - } - - world.getChunkProviderServer().unloadQueue.remove(ChunkCoordIntPair.a(x, z)); - world.getChunkProviderServer().chunks.remove(ChunkCoordIntPair.a(x, z)); - - // Update neighbor counts - for (int xx = -2; xx < 3; xx++) { - for (int zz = -2; zz < 3; zz++) { - if (xx == 0 && zz == 0) { - continue; - } - - net.minecraft.server.Chunk neighbor = world.getChunkProviderServer().getChunkIfLoaded(chunk.locX + x, chunk.locZ + z); - if (neighbor != null) { - neighbor.setNeighborUnloaded(-xx, -zz); - chunk.setNeighborUnloaded(xx, zz); - } - } - } - - return true; + // If chunk had previously been queued to save, must do save to avoid loss of that data + return world.getChunkProviderServer().unloadChunk(chunk, chunk.mustSave || save); } public boolean regenerateChunk(int x, int z) { - unloadChunk0(x, z, false, false); + if (!unloadChunk0(x, z, false)) { + return false; + } - world.getChunkProviderServer().unloadQueue.remove(ChunkCoordIntPair.a(x, z)); + final long chunkKey = ChunkCoordIntPair.a(x, z); + world.getChunkProviderServer().unloadQueue.remove(chunkKey); net.minecraft.server.Chunk chunk = null; @@ -237,9 +216,14 @@ public class CraftWorld implements World { playerChunk.chunk = chunk; } - chunkLoadPostProcess(chunk, x, z); + if (chunk != null) { + world.getChunkProviderServer().chunks.put(chunkKey, chunk); - refreshChunk(x, z); + chunk.addEntities(); + chunk.loadNearby(world.getChunkProviderServer(), world.getChunkProviderServer().chunkGenerator, true); + + refreshChunk(x, z); + } return chunk != null; } @@ -275,39 +259,7 @@ public class CraftWorld implements World { return world.getChunkProviderServer().getChunkAt(x, z) != null; } - world.getChunkProviderServer().unloadQueue.remove(ChunkCoordIntPair.a(x, z)); - net.minecraft.server.Chunk chunk = world.getChunkProviderServer().chunks.get(ChunkCoordIntPair.a(x, z)); - - if (chunk == null) { - chunk = world.getChunkProviderServer().getOrLoadChunkAt(x, z); - } - return chunk != null; - } - - private void chunkLoadPostProcess(net.minecraft.server.Chunk chunk, int cx, int cz) { - if (chunk != null) { - world.getChunkProviderServer().chunks.put(ChunkCoordIntPair.a(cx, cz), chunk); - - chunk.addEntities(); - - // Update neighbor counts - for (int x = -2; x < 3; x++) { - for (int z = -2; z < 3; z++) { - if (x == 0 && z == 0) { - continue; - } - - net.minecraft.server.Chunk neighbor = world.getChunkProviderServer().getLoadedChunkAt(chunk.locX + x, chunk.locZ + z); - if (neighbor != null) { - neighbor.setNeighborLoaded(-x, -z); - chunk.setNeighborLoaded(x, z); - } - } - } - // CraftBukkit end - - chunk.loadNearby(world.getChunkProviderServer(), world.getChunkProviderServer().chunkGenerator); - } + return world.getChunkProviderServer().getOrLoadChunkAt(x, z) != null; } public boolean isChunkLoaded(Chunk chunk) { diff --git a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java index 1632f1366d..f1c1dc4957 100644 --- a/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java +++ b/src/main/java/org/bukkit/craftbukkit/chunkio/ChunkIOProvider.java @@ -48,27 +48,7 @@ class ChunkIOProvider implements AsynchronousExecutor.CallBackProvider