diff --git a/Spigot-Server-Patches/0581-Only-consider-chunks-Loaded-if-at-BORDER-status.patch b/Spigot-Server-Patches/0581-Only-consider-chunks-Loaded-if-at-BORDER-status.patch new file mode 100644 index 000000000..148b996fe --- /dev/null +++ b/Spigot-Server-Patches/0581-Only-consider-chunks-Loaded-if-at-BORDER-status.patch @@ -0,0 +1,156 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Aikar +Date: Sat, 12 Sep 2020 22:20:55 -0400 +Subject: [PATCH] Only consider chunks Loaded if at BORDER status + +This greatly improves performance as it drastically reduces the amount +of Entities and Tile Entities that are "registered" into the world, as +purely "cached" chunks will no longer have their entities hanging out in the world. + +Additionally this fixes our Entity Add To World and Entity Remove From World events + +Those events have not been firing correctly since MC changed how chunks work here. + +Now the server will only consider a chunk "loaded" if it's got a ticket putting +it at level 33 or lower, which matches the public Bukkit API. + +diff --git a/src/main/java/net/minecraft/server/Chunk.java b/src/main/java/net/minecraft/server/Chunk.java +index 299d7d7a55532930e2d4340a6cfe77a5fd8a0a0c..15c0a06139bffc6a7f83a1d47f2a708f14d264ec 100644 +--- a/src/main/java/net/minecraft/server/Chunk.java ++++ b/src/main/java/net/minecraft/server/Chunk.java +@@ -791,6 +791,7 @@ public class Chunk implements IChunkAccess { + int chunkX = this.loc.x; + int chunkZ = this.loc.z; + ChunkProviderServer chunkProvider = ((WorldServer)this.world).getChunkProvider(); ++ chunkProvider.playerChunkMap.loadChunk(this); // Paper - move load logic from the entering full status to when it enters border status instead + for (int dx = -NEIGHBOUR_CACHE_RADIUS; dx <= NEIGHBOUR_CACHE_RADIUS; ++dx) { + for (int dz = -NEIGHBOUR_CACHE_RADIUS; dz <= NEIGHBOUR_CACHE_RADIUS; ++dz) { + Chunk neighbour = chunkProvider.getChunkAtIfLoadedMainThreadNoCache(chunkX + dx, chunkZ + dz); +@@ -862,6 +863,11 @@ public class Chunk implements IChunkAccess { + this.loadedTicketLevel = false; + this.resetNeighbours(); + // Paper end ++ // Paper start - move unload logic from the actual full unload to be when it leaves border status ++ chunkProvider.playerChunkMap.loadedChunks.remove(loc.longKey); ++ setLoaded(false); ++ this.world.unloadChunk(this); ++ // Paper end + } + // CraftBukkit end + +diff --git a/src/main/java/net/minecraft/server/ChunkProviderServer.java b/src/main/java/net/minecraft/server/ChunkProviderServer.java +index 45c142c227bc258bbd5c8c03c6012663dccf8f3f..de5c45ec773474ad6a7b572e9a248c8f8ee0f94f 100644 +--- a/src/main/java/net/minecraft/server/ChunkProviderServer.java ++++ b/src/main/java/net/minecraft/server/ChunkProviderServer.java +@@ -19,6 +19,7 @@ import java.util.function.Supplier; + import javax.annotation.Nullable; + import com.destroystokyo.paper.exception.ServerInternalException; + import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; // Paper ++import it.unimi.dsi.fastutil.longs.LongIterator; // Paper + import org.apache.logging.log4j.LogManager; + import org.apache.logging.log4j.Logger; + +@@ -822,7 +823,10 @@ public class ChunkProviderServer extends IChunkProvider { + //List list = Lists.newArrayList(this.playerChunkMap.f()); // Paper + //Collections.shuffle(list); // Paper + // Paper - moved up +- final int[] chunksTicked = {0}; this.playerChunkMap.forEachVisibleChunk((playerchunk) -> { // Paper - safe iterator incase chunk loads, also no wrapping ++ final int[] chunksTicked = {0}; ++ this.playerChunkMap.forEachVisibleChunk((playerchunk) -> { ++ //for (LongIterator iterator = this.playerChunkMap.loadedChunks.iterator() ; iterator.hasNext() ; ) { // Paper - iterate only loaded chunks ++ //PlayerChunk playerchunk = this.playerChunkMap.getVisibleChunk(iterator.nextLong());// Paper - iterate only loaded chunks + Optional optional = ((Either) playerchunk.a().getNow(PlayerChunk.UNLOADED_CHUNK)).left(); + + if (optional.isPresent()) { +@@ -850,7 +854,7 @@ public class ChunkProviderServer extends IChunkProvider { + } + } + } +- }); ++ });// Paper - use for instead of forEachVisibleChunk + this.world.getMethodProfiler().enter("customSpawners"); + if (flag1) { + try (co.aikar.timings.Timing ignored = this.world.timings.miscMobSpawning.startTiming()) { // Paper - timings +diff --git a/src/main/java/net/minecraft/server/PlayerChunkMap.java b/src/main/java/net/minecraft/server/PlayerChunkMap.java +index fcd3388d88aad6e897b73e2c823267ada327cbda..5d3322f9f068fa74a000d58990dec6001f8ad1ab 100644 +--- a/src/main/java/net/minecraft/server/PlayerChunkMap.java ++++ b/src/main/java/net/minecraft/server/PlayerChunkMap.java +@@ -1021,16 +1021,18 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + this.a(i, playerchunk); + } else { + if (this.pendingUnload.remove(i, playerchunk) && ichunkaccess != null) { ++ // Paper start - coment out and move to ChunkUnloadEvent + if (ichunkaccess instanceof Chunk) { +- ((Chunk) ichunkaccess).setLoaded(false); ++ //((Chunk) ichunkaccess).setLoaded(false); + } + + //this.saveChunk(ichunkaccess);// Paper - delay +- if (this.loadedChunks.remove(i) && ichunkaccess instanceof Chunk) { +- Chunk chunk = (Chunk) ichunkaccess; +- +- this.world.unloadChunk(chunk); +- } ++// if (this.loadedChunks.remove(i) && ichunkaccess instanceof Chunk) { ++// Chunk chunk = (Chunk) ichunkaccess; ++// ++// this.world.unloadChunk(chunk); ++// } ++ // Paper end + this.autoSaveQueue.remove(playerchunk); // Paper + + try { +@@ -1293,6 +1295,20 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + return PlayerChunk.getChunkState(playerchunk.getTicketLevel()); + }); + chunk.addEntities(); ++ // Paper start ++ return chunk; ++ } // Paper ++ }); ++ }, (runnable) -> { ++ ++ this.mailboxMain.a(ChunkTaskQueueSorter.a(runnable, playerchunk.i().pair(), () -> 1)); // Paper - final loads are always urgent! ++ }); ++ } ++ public void loadChunk(Chunk chunk) { ++ if (true) { ++ if (true) { ++ ChunkCoordIntPair chunkcoordintpair = chunk.getPos(); ++ // Paper end + if (this.loadedChunks.add(chunkcoordintpair.pair())) { + chunk.setLoaded(true); + this.world.a(chunk.getTileEntities().values()); +@@ -1328,17 +1344,21 @@ public class PlayerChunkMap extends IChunkLoader implements PlayerChunk.d { + list.forEach(chunk::b); + } + } +- +- return chunk; +- } // Paper +- }); +- }, (runnable) -> { +- Mailbox mailbox = this.mailboxMain; +- long i = playerchunk.i().pair(); +- +- playerchunk.getClass(); +- mailbox.a(ChunkTaskQueueSorter.a(runnable, i, () -> 1)); // Paper - final loads are always urgent! +- }); ++ // Paper start ++ } ++ } ++ // Move code up ++// return chunk; ++// } // Paper ++// }); ++// }, (runnable) -> { ++// Mailbox mailbox = this.mailboxMain; ++// long i = playerchunk.i().pair(); ++// ++// playerchunk.getClass(); ++// mailbox.a(ChunkTaskQueueSorter.a(runnable, i, () -> 1)); // Paper - final loads are always urgent! ++// }); ++ // Paper end + } + + // Paper start