@@ -200,7 +200,7 @@ index 641875899b839d4c0012bd49a3f058258a06d99a..9b3863a7456d3d226a2d53eefdfc109b
200200 final net.minecraft.world.level.levelgen.BitRandomSource simpleRandom = this.simpleRandom; // Paper - optimise random ticking // Leaf - Faster random generator - upcasting
201201 ChunkPos pos = chunk.getPos();
202202diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
203- index bb655318f49242858e2c25d5469705c0c314ed85..a015f0bbff3bb58fd4d28c59620f75dbb125f869 100644
203+ index bb655318f49242858e2c25d5469705c0c314ed85..97a2c3f56dcf1c85cbab6cb3ce2a1fead4f448b1 100644
204204--- a/net/minecraft/world/level/NaturalSpawner.java
205205+++ b/net/minecraft/world/level/NaturalSpawner.java
206206@@ -68,6 +68,7 @@ public final class NaturalSpawner {
@@ -284,7 +284,7 @@ index bb655318f49242858e2c25d5469705c0c314ed85..a015f0bbff3bb58fd4d28c59620f75db
284284 static Biome getRoughBiome(BlockPos pos, ChunkAccess chunk) {
285285 return chunk.getNoiseBiome(QuartPos.fromBlock(pos.getX()), QuartPos.fromBlock(pos.getY()), QuartPos.fromBlock(pos.getZ())).value();
286286 }
287- @@ -265,28 +328,68 @@ public final class NaturalSpawner {
287+ @@ -265,38 +328,78 @@ public final class NaturalSpawner {
288288 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
289289 // Paper PR end - throttle failed spawn attempts
290290 ) {
@@ -303,7 +303,7 @@ index bb655318f49242858e2c25d5469705c0c314ed85..a015f0bbff3bb58fd4d28c59620f75db
303303+ int posZ = pos.getZ();
304304 int i = 0; // Paper PR - throttle failed spawn attempts
305305- BlockState blockState = level.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn
306- + BlockState blockState = level.getWorldBorder().isWithinBounds(pos) ? ( ChunkPos.asLong(pos) == levelChunk.getPos().longKey ? levelChunk.getBlockStateFinal(posX, y, posZ) : level.getBlockStateIfLoaded (pos)) : null ; // Paper - don't load chunks for mob spawn // Leaf
306+ + BlockState blockState = ChunkPos.asLong(pos) == chunk.coordinateKey ? levelChunk.getBlockStateFinal(posX, y, posZ) : level.getBlockStateIfLoadedAndInBounds (pos); // Paper - don't load chunks for mob spawn // Leaf
307307 if (blockState != null && !blockState.isRedstoneConductor(chunk, pos)) { // Paper - don't load chunks for mob spawn
308308 BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
309309 //int i = 0; // Paper PR - throttle failed spawn attempts - move up
@@ -360,9 +360,11 @@ index bb655318f49242858e2c25d5469705c0c314ed85..a015f0bbff3bb58fd4d28c59620f75db
360360 mutableBlockPos.set(x, y, z);
361361 double d = x + 0.5;
362362 double d1 = z + 0.5;
363- @@ -295,8 +398,8 @@ public final class NaturalSpawner {
363+ Player nearestPlayer = level.getNearestPlayer(d, y, d1, -1.0, level.purpurConfig.mobSpawningIgnoreCreativePlayers); // Purpur - mob spawning option to ignore creative players
364+ if (nearestPlayer != null) {
364365 double d2 = nearestPlayer.distanceToSqr(d, y, d1);
365- if (level.isLoadedAndInBounds(mutableBlockPos) && isRightDistanceToPlayerAndSpawnPoint(level, chunk, mutableBlockPos, d2)) { // Paper - don't load chunks for mob spawn
366+ - if (level.isLoadedAndInBounds(mutableBlockPos) && isRightDistanceToPlayerAndSpawnPoint(level, chunk, mutableBlockPos, d2)) { // Paper - don't load chunks for mob spawn
367+ + if ((ChunkPos.asLong(mutableBlockPos) == chunk.coordinateKey || level.isLoadedAndInBounds(mutableBlockPos)) && isRightDistanceToPlayerAndSpawnPoint(level, chunk, mutableBlockPos, d2)) { // Paper - don't load chunks for mob spawn // Leaf - optimize mob spawning
366368 if (spawnerData == null) {
367369- Optional<MobSpawnSettings.SpawnerData> randomSpawnMobAt = getRandomSpawnMobAt(
368370- level, structureManager, generator, category, level.random, mutableBlockPos
@@ -474,7 +476,7 @@ index bb655318f49242858e2c25d5469705c0c314ed85..a015f0bbff3bb58fd4d28c59620f75db
474476+ // Leaf start - optimize mob spawning
475477+ public static boolean isInNetherFortressBoundsChunk(BlockPos pos, ServerLevel level, MobCategory category, StructureManager structureManager, LevelChunk chunk) {
476478+ if (category == MobCategory.MONSTER) {
477- + @Nullable BlockState blockState = chunk.getPos().longKey == ChunkPos.asLong(pos) ? chunk.getBlockStateFinal(pos.getX(), pos.getY() - 1, pos.getZ()) : level.getBlockStateIfLoaded(pos.below());
479+ + @Nullable BlockState blockState = chunk.coordinateKey == ChunkPos.asLong(pos) ? chunk.getBlockStateFinal(pos.getX(), pos.getY() - 1, pos.getZ()) : level.getBlockStateIfLoaded(pos.below());
478480+ if (blockState == null || !blockState.is(Blocks.NETHER_BRICKS)) return false;
479481+ Structure structure = structureManager.registryAccess().lookupOrThrow(Registries.STRUCTURE).getValue(BuiltinStructures.FORTRESS);
480482+ return structure != null && structureManager.getStructureAt(pos, structure).isValid();
@@ -582,7 +584,7 @@ index db3b8a237d63255aa9ffd70c88a093002a6bd770..4a69f404eee00d8972e9501a76031d43
582584 }
583585
584586diff --git a/net/minecraft/world/level/chunk/ChunkGenerator.java b/net/minecraft/world/level/chunk/ChunkGenerator.java
585- index fb77cd58542c1a690cbeaa6ed3a4d657de6e619d..e0267e84c8fd2267b047590d712728e963d165f2 100644
587+ index 2fbf3069cfee45b19276891a21a05d5849ddb70e..0720fe1a1112519dcbfc9f2f0ce123d86d66fc58 100644
586588--- a/net/minecraft/world/level/chunk/ChunkGenerator.java
587589+++ b/net/minecraft/world/level/chunk/ChunkGenerator.java
588590@@ -516,6 +516,35 @@ public abstract class ChunkGenerator {
@@ -591,16 +593,16 @@ index fb77cd58542c1a690cbeaa6ed3a4d657de6e619d..e0267e84c8fd2267b047590d712728e9
591593
592594+ // Leaf start - optimize mob spawning
593595+ public WeightedList<MobSpawnSettings.SpawnerData> getMobsAtChunk(Holder<Biome> biome, StructureManager structureManager, MobCategory category, BlockPos pos, ChunkAccess chunk) {
594- + Map<Structure, LongSet> allStructuresAt = ChunkPos.asLong(pos) == chunk.getPos().longKey ? structureManager.getAllStructuresAtChunk(chunk) : structureManager.getAllStructuresAt(pos);
596+ + Map<Structure, LongSet> allStructuresAt = ChunkPos.asLong(pos) == chunk.coordinateKey ? structureManager.getAllStructuresAtChunk(chunk) : structureManager.getAllStructuresAt(pos);
595597+
596- + for (Entry<Structure, LongSet> entry : allStructuresAt.entrySet()) {
598+ + if (!allStructuresAt.isEmpty()) for (Entry<Structure, LongSet> entry : allStructuresAt.entrySet()) {
597599+ Structure structure = entry.getKey();
598600+ StructureSpawnOverride structureSpawnOverride = structure.spawnOverrides().get(category);
599601+ if (structureSpawnOverride != null) {
600602+ // Leaf start - optimise ChunkGenerator#getMobsAt
601603+ for (long l : entry.getValue()) {
602604+ StructureStart startForStructure = structureManager.getStartForStructure(
603- + null, structure, chunk.getPos().longKey == l ? chunk : structureManager.level.getChunk(ChunkPos.getX(l), ChunkPos.getZ(l), ChunkStatus.STRUCTURE_STARTS)
605+ + null, structure, chunk.coordinateKey == l ? chunk : structureManager.level.getChunk(ChunkPos.getX(l), ChunkPos.getZ(l), ChunkStatus.STRUCTURE_STARTS)
604606+ );
605607+ if (startForStructure != null && startForStructure.isValid()) {
606608+ if (structureSpawnOverride.boundingBox() == StructureSpawnOverride.BoundingBoxType.PIECE
0 commit comments