Skip to content

Commit 76f78af

Browse files
hayanesuruDreeam-qwq
authored andcommitted
fix async mob spawn double compute on non per player mob spawns (#516)
1 parent 2d1834b commit 76f78af

File tree

5 files changed

+53
-72
lines changed

5 files changed

+53
-72
lines changed

leaf-server/minecraft-patches/features/0244-optimize-mob-spawning.patch

Lines changed: 45 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ index 5c8a603e5800e1cc282d899e2a3d6b556295e13c..2dca1ceb886537ff96d0834844429e1c
3030
}
3131
// Paper end - Optional per player mob spawns
3232
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
33-
index 908cd08e33fed1c4cd4bd34c3e63cbbe84ffead4..f5b58c181726536bedabd4b6f64769e312ef4257 100644
33+
index 908cd08e33fed1c4cd4bd34c3e63cbbe84ffead4..e9fd69a3f7a95635361c22f0ecdc558741d3a77f 100644
3434
--- a/net/minecraft/server/level/ServerChunkCache.java
3535
+++ b/net/minecraft/server/level/ServerChunkCache.java
3636
@@ -70,11 +70,11 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
@@ -82,7 +82,7 @@ index 908cd08e33fed1c4cd4bd34c3e63cbbe84ffead4..f5b58c181726536bedabd4b6f64769e3
8282
// Paper start - per player mob spawning backoff
8383
for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) {
8484
player.mobCounts[ii] = 0;
85-
@@ -525,34 +542,27 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
85+
@@ -525,34 +542,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
8686
player.mobBackoffCounts[ii] = newBackoff;
8787
}
8888
// Paper end - per player mob spawning backoff
@@ -92,7 +92,8 @@ index 908cd08e33fed1c4cd4bd34c3e63cbbe84ffead4..f5b58c181726536bedabd4b6f64769e3
9292
firstRunSpawnCounts = false;
9393
_pufferfish_spawnCountsReady.set(true);
9494
}
95-
if (_pufferfish_spawnCountsReady.getAndSet(false)) {
95+
- if (_pufferfish_spawnCountsReady.getAndSet(false)) {
96+
+ if (_pufferfish_spawnCountsReady.getAndSet(false) && level.paperConfig().entities.spawning.perPlayerMobSpawns) {
9697
+ final int mapped = distanceManager.getNaturalSpawnChunkCount();
9798
+ final Iterable<Entity> entities = this.level.getAllEntities();
9899
net.minecraft.server.MinecraftServer.getServer().mobSpawnExecutor.submit(() -> {
@@ -117,30 +118,24 @@ index 908cd08e33fed1c4cd4bd34c3e63cbbe84ffead4..f5b58c181726536bedabd4b6f64769e3
117118
- } finally {
118119
- objectiterator.finishedIterating();
119120
- }
120-
+ // Fix: Use proper mob cap calculator based on configuration
121-
+ LocalMobCapCalculator mobCapCalculator = !level.paperConfig().entities.spawning.perPlayerMobSpawns ?
122-
+ new LocalMobCapCalculator(chunkMap) : null;
123-
+
124121
+ // This ensures the caps are properly enforced by using the correct calculator
125-
+ lastSpawnState = NaturalSpawner.createState1( // Leaf - optimize mob spawning
122+
+ lastSpawnState = NaturalSpawner.createStateAsync( // Leaf - optimize mob spawning
126123
+ mapped,
127124
+ entities,
128-
+ this.level, // Leaf - optimize mob spawning
129-
+ mobCapCalculator, // This is the key fix - was previously null
130-
+ level.paperConfig().entities.spawning.perPlayerMobSpawns
125+
+ this.level
131126
+ );
132127
_pufferfish_spawnCountsReady.set(true);
133128
});
134129
}
135-
@@ -611,6 +621,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
130+
@@ -611,6 +615,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
136131
chunkRange = Math.min(chunkRange, 8);
137132
entityPlayer.playerNaturallySpawnedEvent = new com.destroystokyo.paper.event.entity.PlayerNaturallySpawnCreaturesEvent(entityPlayer.getBukkitEntity(), (byte) chunkRange);
138133
entityPlayer.playerNaturallySpawnedEvent.callEvent();
139134
+ this.level.natureSpawnChunkMap.addPlayer(entityPlayer); // Leaf - optimize mob spawning
140135
}
141136
// Paper end - PlayerNaturallySpawnCreaturesEvent
142137
boolean flag = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getLevelData().getGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit
143-
@@ -622,16 +633,34 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
138+
@@ -622,16 +627,34 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
144139
List<LevelChunk> list = this.spawningChunks;
145140

146141
try {
@@ -178,7 +173,7 @@ index 908cd08e33fed1c4cd4bd34c3e63cbbe84ffead4..f5b58c181726536bedabd4b6f64769e3
178173
list.clear();
179174
}
180175

181-
@@ -649,7 +678,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
176+
@@ -649,7 +672,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
182177
}
183178

184179
if (!spawnCategories.isEmpty()) {
@@ -200,7 +195,7 @@ index 641875899b839d4c0012bd49a3f058258a06d99a..9b3863a7456d3d226a2d53eefdfc109b
200195
final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = this.simpleRandom; // Paper - optimise random ticking // Leaf - Faster random generator - upcasting
201196
ChunkPos pos = chunk.getPos();
202197
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
203-
index bb655318f49242858e2c25d5469705c0c314ed85..97a2c3f56dcf1c85cbab6cb3ce2a1fead4f448b1 100644
198+
index bb655318f49242858e2c25d5469705c0c314ed85..b65616715fa29fdf33f2dfc73650c30f72160f48 100644
204199
--- a/net/minecraft/world/level/NaturalSpawner.java
205200
+++ b/net/minecraft/world/level/NaturalSpawner.java
206201
@@ -68,6 +68,7 @@ public final class NaturalSpawner {
@@ -211,17 +206,13 @@ index bb655318f49242858e2c25d5469705c0c314ed85..97a2c3f56dcf1c85cbab6cb3ce2a1fea
211206
public static NaturalSpawner.SpawnState createState(
212207
int spawnableChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkGetter, LocalMobCapCalculator calculator, final boolean countMobs
213208
) {
214-
@@ -108,9 +109,71 @@ public final class NaturalSpawner {
215-
}
216-
}
217-
218-
- return new NaturalSpawner.SpawnState(spawnableChunkCount, map, potentialCalculator, calculator);
219-
+ return new NaturalSpawner.SpawnState(spawnableChunkCount, map, potentialCalculator, calculator, new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>()); // Leaf - optimize mob spawning
209+
@@ -111,6 +112,46 @@ public final class NaturalSpawner {
210+
return new NaturalSpawner.SpawnState(spawnableChunkCount, map, potentialCalculator, calculator);
220211
}
221212

222213
+ // Leaf start - optimize mob spawning
223-
+ public static NaturalSpawner.SpawnState createState1(
224-
+ int spawnableChunkCount, Iterable<Entity> entities, ServerLevel level, LocalMobCapCalculator calculator, final boolean countMobs
214+
+ public static NaturalSpawner.SpawnState createStateAsync(
215+
+ int spawnableChunkCount, Iterable<Entity> entities, ServerLevel level
225216
+ ) {
226217
+ // Paper end - Optional per player mob spawns
227218
+ PotentialCalculator potentialCalculator = new PotentialCalculator();
@@ -247,44 +238,22 @@ index bb655318f49242858e2c25d5469705c0c314ed85..97a2c3f56dcf1c85cbab6cb3ce2a1fea
247238
+ potentialCalculator.addCharge(entity.blockPosition(), mobSpawnCost.charge());
248239
+ }
249240
+
250-
+ if (calculator != null && entity instanceof Mob) { // Paper - Optional per player mob spawns
251-
+ calculator.addMob(chunk.getPos(), category);
252-
+ }
253-
+
254241
+ map.addTo(category, 1);
255-
+ // Paper start - Optional per player mob spawns
256-
+ if (countMobs) {
257-
+ final int index = entity.getType().getCategory().ordinal();
258-
+ ++chunkCap.computeIfAbsent(chunk.getPos().longKey, k -> new int[net.minecraft.server.level.ServerPlayer.MOBCATEGORY_TOTAL_ENUMS])[index];
259-
+ /*
260242
+ final int index = entity.getType().getCategory().ordinal();
261-
+ final var inRange = level.moonrise$getNearbyPlayers().getPlayers(entity.chunkPosition(), NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
262-
+ if (inRange == null) {
263-
+ continue;
264-
+ }
265-
+
266-
+ final net.minecraft.server.level.ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
267-
+ for (int i = 0, len = inRange.size(); i < len; i++) {
268-
+ final net.minecraft.server.level.ServerPlayer player = backingSet[i];
269-
+ if (player == null) continue;
270-
+ ++playerCap.computeIfAbsent(player, k -> new int[net.minecraft.server.level.ServerPlayer.MOBCATEGORY_TOTAL_ENUMS])[index];
271-
+ }
272-
+ */
273-
+ }
274-
+ // Paper end - Optional per player mob spawns
243+
+ ++chunkCap.computeIfAbsent(chunk.coordinateKey, k -> new int[net.minecraft.server.level.ServerPlayer.MOBCATEGORY_TOTAL_ENUMS])[index];
275244
+ }
276245
+ }
277246
+ }
278247
+ }
279248
+
280-
+ return new NaturalSpawner.SpawnState(spawnableChunkCount, map, potentialCalculator, calculator, chunkCap);
249+
+ return new NaturalSpawner.SpawnState(spawnableChunkCount, map, potentialCalculator, null, chunkCap);
281250
+ }
282251
+ // Leaf end - optimize mob spawning
283252
+
284253
static Biome getRoughBiome(BlockPos pos, ChunkAccess chunk) {
285254
return chunk.getNoiseBiome(QuartPos.fromBlock(pos.getX()), QuartPos.fromBlock(pos.getY()), QuartPos.fromBlock(pos.getZ())).value();
286255
}
287-
@@ -265,38 +328,78 @@ public final class NaturalSpawner {
256+
@@ -265,38 +306,78 @@ public final class NaturalSpawner {
288257
MobCategory category, ServerLevel level, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final @Nullable Consumer<Entity> trackEntity, final boolean nothing
289258
// Paper PR end - throttle failed spawn attempts
290259
) {
@@ -373,7 +342,7 @@ index bb655318f49242858e2c25d5469705c0c314ed85..97a2c3f56dcf1c85cbab6cb3ce2a1fea
373342
);
374343
if (randomSpawnMobAt.isEmpty()) {
375344
break;
376-
@@ -307,7 +410,7 @@ public final class NaturalSpawner {
345+
@@ -307,7 +388,7 @@ public final class NaturalSpawner {
377346
}
378347

379348
// Paper start - PreCreatureSpawnEvent
@@ -382,7 +351,7 @@ index bb655318f49242858e2c25d5469705c0c314ed85..97a2c3f56dcf1c85cbab6cb3ce2a1fea
382351
// Paper start - per player mob count backoff
383352
if (doSpawning == PreSpawnStatus.ABORT || doSpawning == PreSpawnStatus.CANCELLED) {
384353
level.getChunkSource().chunkMap.updateFailurePlayerMobTypeMap(mutableBlockPos.getX() >> 4, mutableBlockPos.getZ() >> 4, category);
385-
@@ -414,6 +517,44 @@ public final class NaturalSpawner {
354+
@@ -414,6 +495,44 @@ public final class NaturalSpawner {
386355
&& level.noCollision(entityType.getSpawnAABB(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5));
387356
return success ? PreSpawnStatus.SUCCESS : PreSpawnStatus.FAIL; // Paper - PreCreatureSpawnEvent
388357
}
@@ -427,7 +396,7 @@ index bb655318f49242858e2c25d5469705c0c314ed85..97a2c3f56dcf1c85cbab6cb3ce2a1fea
427396

428397
@Nullable
429398
private static Mob getMobForSpawn(ServerLevel level, EntityType<?> entityType) {
430-
@@ -449,6 +590,17 @@ public final class NaturalSpawner {
399+
@@ -449,6 +568,17 @@ public final class NaturalSpawner {
431400
: mobsAt(level, structureManager, generator, category, pos, biome).getRandom(random);
432401
}
433402

@@ -445,7 +414,7 @@ index bb655318f49242858e2c25d5469705c0c314ed85..97a2c3f56dcf1c85cbab6cb3ce2a1fea
445414
private static boolean canSpawnMobAt(
446415
ServerLevel level, StructureManager structureManager, ChunkGenerator generator, MobCategory category, MobSpawnSettings.SpawnerData data, BlockPos pos
447416
) {
448-
@@ -463,8 +615,22 @@ public final class NaturalSpawner {
417+
@@ -463,8 +593,22 @@ public final class NaturalSpawner {
449418
: generator.getMobsAt(biome != null ? biome : (org.dreeam.leaf.config.modules.opt.OptimizeBiome.mobSpawn ? level.getBiomeCached(null, pos) : level.getBiome(pos)), structureManager, cetagory, pos); // Leaf - cache getBiome
450419
}
451420

@@ -469,7 +438,7 @@ index bb655318f49242858e2c25d5469705c0c314ed85..97a2c3f56dcf1c85cbab6cb3ce2a1fea
469438
Structure structure = structureManager.registryAccess().lookupOrThrow(Registries.STRUCTURE).getValue(BuiltinStructures.FORTRESS);
470439
return structure != null && structureManager.getStructureAt(pos, structure).isValid();
471440
} else {
472-
@@ -472,6 +638,19 @@ public final class NaturalSpawner {
441+
@@ -472,6 +616,19 @@ public final class NaturalSpawner {
473442
}
474443
}
475444

@@ -489,30 +458,42 @@ index bb655318f49242858e2c25d5469705c0c314ed85..97a2c3f56dcf1c85cbab6cb3ce2a1fea
489458
private static BlockPos getRandomPosWithin(Level level, LevelChunk chunk) {
490459
ChunkPos pos = chunk.getPos();
491460
int i = pos.getMinBlockX() + level.random.nextInt(16);
492-
@@ -612,18 +791,21 @@ public final class NaturalSpawner {
461+
@@ -612,6 +769,7 @@ public final class NaturalSpawner {
493462
@Nullable
494463
private EntityType<?> lastCheckedType;
495464
private double lastCharge;
496465
+ public final it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<int[]> chunkCap; // Leaf - optimize mob spawning
497466

498467
SpawnState(
499468
int spawnableChunkCount,
500-
Object2IntOpenHashMap<MobCategory> mobCategoryCounts,
501-
PotentialCalculator spawnPotential,
502-
- LocalMobCapCalculator localMobCapCalculator
503-
+ LocalMobCapCalculator localMobCapCalculator,
504-
+ it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<int[]> playerCap // Leaf - optimize mob spawning
505-
) {
506-
this.spawnableChunkCount = spawnableChunkCount;
507-
this.mobCategoryCounts = mobCategoryCounts;
469+
@@ -624,8 +782,26 @@ public final class NaturalSpawner {
508470
this.spawnPotential = spawnPotential;
509471
this.localMobCapCalculator = localMobCapCalculator;
510472
this.unmodifiableMobCategoryCounts = Object2IntMaps.unmodifiable(mobCategoryCounts);
511-
+ this.chunkCap = playerCap; // Leaf - optimize mob spawning
473+
+ this.chunkCap = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>(); // Leaf - optimize mob spawning
512474
}
513475

476+
+ // Leaf start - optimize mob spawning
477+
+ SpawnState(
478+
+ int spawnableChunkCount,
479+
+ Object2IntOpenHashMap<MobCategory> mobCategoryCounts,
480+
+ PotentialCalculator spawnPotential,
481+
+ LocalMobCapCalculator localMobCapCalculator,
482+
+ it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<int[]> playerCap
483+
+ ) {
484+
+ this.spawnableChunkCount = spawnableChunkCount;
485+
+ this.mobCategoryCounts = mobCategoryCounts;
486+
+ this.spawnPotential = spawnPotential;
487+
+ this.localMobCapCalculator = localMobCapCalculator;
488+
+ this.unmodifiableMobCategoryCounts = Object2IntMaps.unmodifiable(mobCategoryCounts);
489+
+ this.chunkCap = playerCap;
490+
+ }
491+
+ // Leaf end - optimize mob spawning
492+
+
514493
private boolean canSpawn(EntityType<?> entityType, BlockPos pos, ChunkAccess chunk) {
515-
@@ -680,5 +862,32 @@ public final class NaturalSpawner {
494+
this.lastCheckedPos = pos;
495+
this.lastCheckedType = entityType;
496+
@@ -680,5 +856,32 @@ public final class NaturalSpawner {
516497
boolean canSpawnForCategoryLocal(MobCategory category, ChunkPos chunkPos) {
517498
return this.localMobCapCalculator.canSpawn(category, chunkPos);
518499
}

leaf-server/minecraft-patches/features/0246-throttle-mob-spawning.patch

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ Subject: [PATCH] throttle mob spawning
55

66

77
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
8-
index a015f0bbff3bb58fd4d28c59620f75dbb125f869..388a22d4ce37f1471fb906118d9e2135d7789834 100644
8+
index ea120c7737ba82586c46ad091a4bf0ceeb2e81e3..6c6d768d4aa5a8c90bff2433489d777c5e66069b 100644
99
--- a/net/minecraft/world/level/NaturalSpawner.java
1010
+++ b/net/minecraft/world/level/NaturalSpawner.java
11-
@@ -217,6 +217,17 @@ public final class NaturalSpawner {
11+
@@ -195,6 +195,17 @@ public final class NaturalSpawner {
1212
// Paper start - Optional per player mob spawns
1313
final boolean canSpawn;
1414
int maxSpawns = Integer.MAX_VALUE;

leaf-server/minecraft-patches/features/0251-optimize-random-tick.patch

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ Subject: [PATCH] optimize random tick
55

66

77
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
8-
index f5b58c181726536bedabd4b6f64769e312ef4257..2847aa24cca82b1c66b69600ddcb5dbdadec5b9d 100644
8+
index 0e90863dbb3cf918f0091c1a64b3d02f566fef35..357aaaa848dd6e47793e75225f690d2770a6cd4a 100644
99
--- a/net/minecraft/server/level/ServerChunkCache.java
1010
+++ b/net/minecraft/server/level/ServerChunkCache.java
11-
@@ -664,7 +664,13 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
11+
@@ -658,7 +658,13 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
1212
list.clear();
1313
}
1414

leaf-server/minecraft-patches/features/0257-Paw-optimization.patch

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ index 4535858701b2bb232b9d2feb2af6551526232ddc..e65c62dbe4c1560ae153e4c4344e9194
100100
- // Paper end - detailed watchdog information
101101
}
102102
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
103-
index 2847aa24cca82b1c66b69600ddcb5dbdadec5b9d..bd4c98e9ec41a2bd608e2e2245c503be3171ceee 100644
103+
index 357aaaa848dd6e47793e75225f690d2770a6cd4a..cc7f3f8487db241b235e5f49d8bab3eb635f6a37 100644
104104
--- a/net/minecraft/server/level/ServerChunkCache.java
105105
+++ b/net/minecraft/server/level/ServerChunkCache.java
106-
@@ -638,8 +638,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
106+
@@ -632,8 +632,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
107107
this.level.natureSpawnChunkMap.build();
108108
this.level.natureSpawnChunkMap.collectSpawningChunks(this.level.moonrise$getPlayerTickingChunks(), list);
109109
// Paper start - chunk tick iteration optimisation

leaf-server/minecraft-patches/features/0274-Skip-PreCreatureSpawnEvent-if-no-listeners.patch

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@ Subject: [PATCH] Skip PreCreatureSpawnEvent if no listeners
55

66

77
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
8-
index 388a22d4ce37f1471fb906118d9e2135d7789834..12731a0026531e33f28ce4b3ba1e690e2fc0b119 100644
8+
index 6c6d768d4aa5a8c90bff2433489d777c5e66069b..ec2f630b8eeed85e81b730e3a3d339b3419f39e8 100644
99
--- a/net/minecraft/world/level/NaturalSpawner.java
1010
+++ b/net/minecraft/world/level/NaturalSpawner.java
11-
@@ -541,17 +541,35 @@ public final class NaturalSpawner {
11+
@@ -519,17 +519,35 @@ public final class NaturalSpawner {
1212
LevelChunk chunk
1313
) {
1414
EntityType<?> entityType = data.type();

0 commit comments

Comments
 (0)