From c9bbb9ab4edd52455a9230b79d5f00d4395e3624 Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Sun, 5 Dec 2021 06:00:13 -0800 Subject: [PATCH] Update Optimise chunk tick iteration (#6950) --- patches/server/MC-Utils.patch | 9 -- .../Optimise-chunk-tick-iteration.patch | 106 ++++++++++++++++++ ...erCloseEnoughForSpawning-to-use-dist.patch | 2 +- .../PlayerNaturallySpawnCreaturesEvent.patch | 2 +- 4 files changed, 108 insertions(+), 11 deletions(-) create mode 100644 patches/server/Optimise-chunk-tick-iteration.patch diff --git a/patches/server/MC-Utils.patch b/patches/server/MC-Utils.patch index 06973c8844..b8121ff30e 100644 --- a/patches/server/MC-Utils.patch +++ b/patches/server/MC-Utils.patch @@ -5874,15 +5874,6 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @Nullable @Override public ChunkAccess getChunk(int x, int z, ChunkStatus leastStatus, boolean create) { -@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { - gameprofilerfiller.popPush("spawnAndTick"); - boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit - -- Collections.shuffle(list); -+ //Collections.shuffle(list); // Paper - no... just no... - Iterator iterator1 = list.iterator(); - - while (iterator1.hasNext()) { diff --git a/src/main/java/net/minecraft/server/level/ServerLevel.java b/src/main/java/net/minecraft/server/level/ServerLevel.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/server/level/ServerLevel.java diff --git a/patches/server/Optimise-chunk-tick-iteration.patch b/patches/server/Optimise-chunk-tick-iteration.patch new file mode 100644 index 0000000000..8b77a5ffb0 --- /dev/null +++ b/patches/server/Optimise-chunk-tick-iteration.patch @@ -0,0 +1,106 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Spottedleaf +Date: Thu, 7 May 2020 05:48:54 -0700 +Subject: [PATCH] Optimise chunk tick iteration + +Use a dedicated list of entity ticking chunks to reduce the cost + +diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 +--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java ++++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java +@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { + + this.lastSpawnState = spawnercreature_d; + gameprofilerfiller.popPush("filteringLoadedChunks"); +- List list = Lists.newArrayListWithCapacity(l); +- Iterator iterator = this.chunkMap.getChunks().iterator(); ++ // Paper - moved down + this.level.timings.chunkTicks.startTiming(); // Paper + +- while (iterator.hasNext()) { +- ChunkHolder playerchunk = (ChunkHolder) iterator.next(); +- LevelChunk chunk = playerchunk.getTickingChunk(); +- +- if (chunk != null) { +- list.add(new ServerChunkCache.ChunkAndHolder(chunk, playerchunk)); +- } +- } ++ // Paper - moved down + + gameprofilerfiller.popPush("spawnAndTick"); + boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit + +- Collections.shuffle(list); ++ // Paper - only shuffle if per-player mob spawning is disabled + // Paper - moved natural spawn event up +- Iterator iterator1 = list.iterator(); ++ // Paper start - optimise chunk tick iteration ++ Iterator iterator1; ++ if (this.level.paperConfig.perPlayerMobSpawns) { ++ iterator1 = this.entityTickingChunks.iterator(); ++ } else { ++ iterator1 = this.entityTickingChunks.unsafeIterator(); ++ List shuffled = Lists.newArrayListWithCapacity(this.entityTickingChunks.size()); ++ while (iterator1.hasNext()) { ++ shuffled.add(iterator1.next()); ++ } ++ Collections.shuffle(shuffled); ++ iterator1 = shuffled.iterator(); ++ } + ++ try { + while (iterator1.hasNext()) { +- ServerChunkCache.ChunkAndHolder chunkproviderserver_a = (ServerChunkCache.ChunkAndHolder) iterator1.next(); +- LevelChunk chunk1 = chunkproviderserver_a.chunk; ++ LevelChunk chunk1 = iterator1.next(); ++ ChunkHolder holder = chunk1.playerChunk; ++ if (holder != null) { ++ gameprofilerfiller.popPush("broadcast"); ++ this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing ++ holder.broadcastChanges(chunk1); ++ this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing ++ gameprofilerfiller.pop(); ++ // Paper end - optimise chunk tick iteration + ChunkPos chunkcoordintpair = chunk1.getPos(); + +- if (this.level.isPositionEntityTicking(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkproviderserver_a.holder, chunkcoordintpair, false)) { // Paper - optimise anyPlayerCloseEnoughForSpawning ++ if ((true || this.level.isPositionEntityTicking(chunkcoordintpair)) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, false)) { // Paper - optimise anyPlayerCloseEnoughForSpawning & optimise chunk tick iteration + chunk1.incrementInhabitedTime(j); +- if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(chunkproviderserver_a.holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning ++ if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning & optimise chunk tick iteration + NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1); + } + +@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { + this.level.tickChunk(chunk1, k); + } + } ++ // Paper start - optimise chunk tick iteration ++ } + } ++ ++ } finally { ++ if (iterator1 instanceof io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator safeIterator) { ++ safeIterator.finishedIterating(); ++ } ++ } ++ // Paper end - optimise chunk tick iteration + this.level.timings.chunkTicks.stopTiming(); // Paper + gameprofilerfiller.popPush("customSpawners"); + if (flag2) { +@@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { + } // Paper - timings + } + +- gameprofilerfiller.popPush("broadcast"); +- list.forEach((chunkproviderserver_a1) -> { +- this.level.timings.broadcastChunkUpdates.startTiming(); // Paper - timing +- chunkproviderserver_a1.holder.broadcastChanges(chunkproviderserver_a1.chunk); +- this.level.timings.broadcastChunkUpdates.stopTiming(); // Paper - timing +- }); +- gameprofilerfiller.pop(); ++ // Paper - no, iterating just ONCE is expensive enough! Don't do it TWICE! Code moved up + gameprofilerfiller.pop(); + // Paper start - controlled flush for entity tracker packets + List disabledFlushes = new java.util.ArrayList<>(this.level.players.size()); diff --git a/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch b/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch index 72517c4ac8..1e2ab1940b 100644 --- a/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch +++ b/patches/server/Optimize-anyPlayerCloseEnoughForSpawning-to-use-dist.patch @@ -316,7 +316,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit - //Collections.shuffle(list); // Paper - no... just no... + Collections.shuffle(list); - // Paper start - call player naturally spawn event - int chunkRange = level.spigotConfig.mobSpawnRange; - chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange; diff --git a/patches/server/PlayerNaturallySpawnCreaturesEvent.patch b/patches/server/PlayerNaturallySpawnCreaturesEvent.patch index c30c7823f9..00d671a433 100644 --- a/patches/server/PlayerNaturallySpawnCreaturesEvent.patch +++ b/patches/server/PlayerNaturallySpawnCreaturesEvent.patch @@ -46,7 +46,7 @@ index 0000000000000000000000000000000000000000..00000000000000000000000000000000 @@ -0,0 +0,0 @@ public class ServerChunkCache extends ChunkSource { boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit - //Collections.shuffle(list); // Paper - no... just no... + Collections.shuffle(list); + // Paper start - call player naturally spawn event + int chunkRange = level.spigotConfig.mobSpawnRange; + chunkRange = (chunkRange > level.spigotConfig.viewDistance) ? (byte) level.spigotConfig.viewDistance : chunkRange;