107 lines
6.3 KiB
Diff
107 lines
6.3 KiB
Diff
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||
|
From: Spottedleaf <spottedleaf@spottedleaf.dev>
|
||
|
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 51c4ca36221e9af074fa92f6ab94fa7ba5403080..ca16bde30da84e79fef856304ada9e3b8bfb9806 100644
|
||
|
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||
|
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
|
||
|
@@ -1001,34 +1001,46 @@ public class ServerChunkCache extends ChunkSource {
|
||
|
|
||
|
this.lastSpawnState = spawnercreature_d;
|
||
|
gameprofilerfiller.popPush("filteringLoadedChunks");
|
||
|
- List<ServerChunkCache.ChunkAndHolder> 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<LevelChunk> iterator1;
|
||
|
+ if (this.level.paperConfig.perPlayerMobSpawns) {
|
||
|
+ iterator1 = this.entityTickingChunks.iterator();
|
||
|
+ } else {
|
||
|
+ iterator1 = this.entityTickingChunks.unsafeIterator();
|
||
|
+ List<LevelChunk> 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);
|
||
|
}
|
||
|
|
||
|
@@ -1036,7 +1048,16 @@ 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) {
|
||
|
@@ -1045,13 +1066,7 @@ 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<net.minecraft.network.Connection> disabledFlushes = new java.util.ArrayList<>(this.level.players.size());
|