From b90c1cd527d2fbd708845b1326eae18e9d988a29 Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Fri, 27 Jun 2025 23:53:52 +0900 Subject: [PATCH] fix playermobcaps command --- ...tBiome.patch => 0261-cache-getBiome.patch} | 93 ++++++++++++--- .../features/0262-optimize-mob-spawning.patch | 112 +++++++++++++----- .../features/0269-optimize-random-tick.patch | 4 +- .../features/0272-Paw-optimization.patch | 6 +- .../features/0055-cache-getBiome.patch | 6 +- 5 files changed, 172 insertions(+), 49 deletions(-) rename leaf-server/minecraft-patches/features/{0261-optimise-getBiome.patch => 0261-cache-getBiome.patch} (56%) diff --git a/leaf-server/minecraft-patches/features/0261-optimise-getBiome.patch b/leaf-server/minecraft-patches/features/0261-cache-getBiome.patch similarity index 56% rename from leaf-server/minecraft-patches/features/0261-optimise-getBiome.patch rename to leaf-server/minecraft-patches/features/0261-cache-getBiome.patch index d52b0083..592665d7 100644 --- a/leaf-server/minecraft-patches/features/0261-optimise-getBiome.patch +++ b/leaf-server/minecraft-patches/features/0261-cache-getBiome.patch @@ -1,11 +1,11 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Tue, 3 Jun 2025 15:20:40 +0900 -Subject: [PATCH] optimise getBiome +Subject: [PATCH] cache getBiome diff --git a/net/minecraft/advancements/critereon/LocationPredicate.java b/net/minecraft/advancements/critereon/LocationPredicate.java -index a26a5311f87873e0d4d26fda9cb8956a32ee81e8..65e4315cce35814c60b21bbd5baea2ffac82162c 100644 +index a26a5311f87873e0d4d26fda9cb8956a32ee81e8..7ba5c85bbce8528a4df072e63948673300630a9d 100644 --- a/net/minecraft/advancements/critereon/LocationPredicate.java +++ b/net/minecraft/advancements/critereon/LocationPredicate.java @@ -49,7 +49,7 @@ public record LocationPredicate( @@ -13,12 +13,12 @@ index a26a5311f87873e0d4d26fda9cb8956a32ee81e8..65e4315cce35814c60b21bbd5baea2ff BlockPos blockPos = BlockPos.containing(x, y, z); boolean isLoaded = level.isLoaded(blockPos); - return (!this.biomes.isPresent() || isLoaded && this.biomes.get().contains(level.getBiome(blockPos))) -+ return (!this.biomes.isPresent() || isLoaded && this.biomes.get().contains(org.dreeam.leaf.config.modules.opt.OptimizeBiome.advancement ? level.getBiomeCached(blockPos) : level.getBiome(blockPos))) // Leaf - cache getBiome ++ return (!this.biomes.isPresent() || isLoaded && this.biomes.get().contains(org.dreeam.leaf.config.modules.opt.OptimizeBiome.advancement ? level.getBiomeCached(null, blockPos) : level.getBiome(blockPos))) // Leaf - cache getBiome && (!this.structures.isPresent() || isLoaded && level.structureManager().getStructureWithPieceAt(blockPos, this.structures.get()).isValid()) && (!this.smokey.isPresent() || isLoaded && this.smokey.get() == CampfireBlock.isSmokeyPos(level, blockPos)) && (!this.light.isPresent() || this.light.get().matches(level, blockPos)) diff --git a/net/minecraft/world/level/LevelReader.java b/net/minecraft/world/level/LevelReader.java -index 0842fd6488c8b27d98c4344e1244996b4c0e9912..c6ddb49648c55443ae880c1adba9887ab0681c82 100644 +index 0842fd6488c8b27d98c4344e1244996b4c0e9912..55c7f7486c293d4434b7e3facdbef034d105aa19 100644 --- a/net/minecraft/world/level/LevelReader.java +++ b/net/minecraft/world/level/LevelReader.java @@ -57,6 +57,12 @@ public interface LevelReader extends ca.spottedleaf.moonrise.patches.chunk_syste @@ -26,8 +26,8 @@ index 0842fd6488c8b27d98c4344e1244996b4c0e9912..c6ddb49648c55443ae880c1adba9887a } + // Leaf start - cache getBiome -+ default Holder getBiomeCached(BlockPos pos) { -+ return this.getBiomeManager().getBiomeCached(pos); ++ default Holder getBiomeCached(@Nullable net.minecraft.world.level.chunk.LevelChunk chunk, BlockPos pos) { ++ return this.getBiomeManager().getBiomeCached(chunk, pos); + } + // Leaf end - cache getBiome + @@ -35,7 +35,7 @@ index 0842fd6488c8b27d98c4344e1244996b4c0e9912..c6ddb49648c55443ae880c1adba9887a int floor = Mth.floor(aabb.minX); int floor1 = Mth.floor(aabb.maxX); diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java -index a2da4fce50f31d56036d04041c4f80ed90c18b27..f242941ce06d356a025e306efe78c688e9b755c4 100644 +index a2da4fce50f31d56036d04041c4f80ed90c18b27..81e176d17fb072f9ee531639abfe42134ae833a9 100644 --- a/net/minecraft/world/level/NaturalSpawner.java +++ b/net/minecraft/world/level/NaturalSpawner.java @@ -443,7 +443,7 @@ public final class NaturalSpawner { @@ -43,7 +43,7 @@ index a2da4fce50f31d56036d04041c4f80ed90c18b27..f242941ce06d356a025e306efe78c688 ServerLevel level, StructureManager structureManager, ChunkGenerator generator, MobCategory category, RandomSource random, BlockPos pos ) { - Holder biome = level.getBiome(pos); -+ Holder biome = org.dreeam.leaf.config.modules.opt.OptimizeBiome.mobSpawn ? level.getBiomeCached(pos) : level.getBiome(pos); // Leaf - cache getBiome ++ Holder biome = org.dreeam.leaf.config.modules.opt.OptimizeBiome.mobSpawn ? level.getBiomeCached(null, pos) : level.getBiome(pos); // Leaf - cache getBiome return category == MobCategory.WATER_AMBIENT && biome.is(BiomeTags.REDUCED_WATER_AMBIENT_SPAWNS) && random.nextFloat() < 0.98F ? Optional.empty() : mobsAt(level, structureManager, generator, category, pos, biome).getRandom(random); @@ -52,12 +52,12 @@ index a2da4fce50f31d56036d04041c4f80ed90c18b27..f242941ce06d356a025e306efe78c688 return isInNetherFortressBounds(pos, level, cetagory, structureManager) ? NetherFortressStructure.FORTRESS_ENEMIES - : generator.getMobsAt(biome != null ? biome : level.getBiome(pos), structureManager, cetagory, pos); -+ : generator.getMobsAt(biome != null ? biome : (org.dreeam.leaf.config.modules.opt.OptimizeBiome.mobSpawn ? level.getBiomeCached(pos) : level.getBiome(pos)), structureManager, cetagory, pos); // Leaf - cache getBiome ++ : 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 } public static boolean isInNetherFortressBounds(BlockPos pos, ServerLevel level, MobCategory category, StructureManager structureManager) { diff --git a/net/minecraft/world/level/biome/BiomeManager.java b/net/minecraft/world/level/biome/BiomeManager.java -index a48175a7ebb1788ace46395621ed78d910178a53..00122472991ba0c1a0ea77053aad71cdfa92a7bd 100644 +index a48175a7ebb1788ace46395621ed78d910178a53..bda44479d1537d9fa2d23f519049aeb96685fbe6 100644 --- a/net/minecraft/world/level/biome/BiomeManager.java +++ b/net/minecraft/world/level/biome/BiomeManager.java @@ -15,10 +15,23 @@ public class BiomeManager { @@ -84,12 +84,12 @@ index a48175a7ebb1788ace46395621ed78d910178a53..00122472991ba0c1a0ea77053aad71cd } public static long obfuscateSeed(long seed) { -@@ -29,6 +42,40 @@ public class BiomeManager { +@@ -29,6 +42,105 @@ public class BiomeManager { return new BiomeManager(newSource, this.biomeZoomSeed); } + // Leaf start - cache getBiome -+ public Holder getBiomeCached(BlockPos pos) { ++ public Holder getBiomeCached(@org.jetbrains.annotations.Nullable net.minecraft.world.level.chunk.LevelChunk chunk, BlockPos pos) { + if (biomeCache == null) { + return getBiome(pos); + } @@ -113,19 +113,84 @@ index a48175a7ebb1788ace46395621ed78d910178a53..00122472991ba0c1a0ea77053aad71cd + } + } + -+ Holder biome = getBiome(pos); ++ Holder biome = getBiomeCachedChunk(chunk, pos); + + biomeCache[(int) hash] = biome; + biomeCachePos[(int) hash] = packedPos; + + return biome; + } ++ private Holder getBiomeCachedChunk(@org.jetbrains.annotations.Nullable net.minecraft.world.level.chunk.LevelChunk chunk, BlockPos pos) { ++ // Leaf start - Carpet-Fixes - Optimized getBiome method ++ int xMinus2 = pos.getX() - 2; ++ int yMinus2 = pos.getY() - 2; ++ int zMinus2 = pos.getZ() - 2; ++ int x = xMinus2 >> 2; // BlockPos to BiomePos ++ int y = yMinus2 >> 2; ++ int z = zMinus2 >> 2; ++ double quartX = (double) (xMinus2 & 3) / 4.0; // quartLocal divided by 4 ++ double quartY = (double) (yMinus2 & 3) / 4.0; // 0/4, 1/4, 2/4, 3/4 ++ double quartZ = (double) (zMinus2 & 3) / 4.0; // [0, 0.25, 0.5, 0.75] ++ int smallestX = 0; ++ double smallestDist = Double.POSITIVE_INFINITY; ++ for (int biomeX = 0; biomeX < 8; ++biomeX) { ++ boolean everyOtherQuad = (biomeX & 4) == 0; // 1 1 1 1 0 0 0 0 ++ boolean everyOtherPair = (biomeX & 2) == 0; // 1 1 0 0 1 1 0 0 ++ boolean everyOther = (biomeX & 1) == 0; // 1 0 1 0 1 0 1 0 ++ double quartXX = everyOtherQuad ? quartX : quartX - 1.0; //[-1.0,-0.75,-0.5,-0.25,0.0,0.25,0.5,0.75] ++ double quartYY = everyOtherPair ? quartY : quartY - 1.0; ++ double quartZZ = everyOther ? quartZ : quartZ - 1.0; ++ ++ //This code block is new ++ double maxQuartYY = 0.0, maxQuartZZ = 0.0; ++ if (biomeX != 0) { ++ maxQuartYY = Mth.square(Math.max(quartYY + maxOffset, Math.abs(quartYY - maxOffset))); ++ maxQuartZZ = Mth.square(Math.max(quartZZ + maxOffset, Math.abs(quartZZ - maxOffset))); ++ double maxQuartXX = Mth.square(Math.max(quartXX + maxOffset, Math.abs(quartXX - maxOffset))); ++ if (smallestDist < maxQuartXX + maxQuartYY + maxQuartZZ) continue; ++ } ++ int xx = everyOtherQuad ? x : x + 1; ++ int yy = everyOtherPair ? y : y + 1; ++ int zz = everyOther ? z : z + 1; ++ ++ //I transferred the code from method_38106 to here, so I could call continue halfway through ++ long seed = LinearCongruentialGenerator.next(this.biomeZoomSeed, xx); ++ seed = LinearCongruentialGenerator.next(seed, yy); ++ seed = LinearCongruentialGenerator.next(seed, zz); ++ seed = LinearCongruentialGenerator.next(seed, xx); ++ seed = LinearCongruentialGenerator.next(seed, yy); ++ seed = LinearCongruentialGenerator.next(seed, zz); ++ double offsetX = getFiddle(seed); ++ double sqrX = Mth.square(quartXX + offsetX); ++ if (biomeX != 0 && smallestDist < sqrX + maxQuartYY + maxQuartZZ) continue; //skip the rest of the loop ++ seed = LinearCongruentialGenerator.next(seed, this.biomeZoomSeed); ++ double offsetY = getFiddle(seed); ++ double sqrY = Mth.square(quartYY + offsetY); ++ if (biomeX != 0 && smallestDist < sqrX + sqrY + maxQuartZZ) continue; // skip the rest of the loop ++ seed = LinearCongruentialGenerator.next(seed, this.biomeZoomSeed); ++ double offsetZ = getFiddle(seed); ++ double biomeDist = sqrX + sqrY + Mth.square(quartZZ + offsetZ); ++ ++ if (smallestDist > biomeDist) { ++ smallestX = biomeX; ++ smallestDist = biomeDist; ++ } ++ } ++ int x1 = (smallestX & 4) == 0 ? x : x + 1; ++ int y1 = (smallestX & 2) == 0 ? y : y + 1; ++ int z1 = (smallestX & 1) == 0 ? z : z + 1; ++ if (chunk != null && chunk.locX == x >> 2 && chunk.locZ == z >> 2) { ++ return chunk.getNoiseBiome(x1, y1, z1); ++ } ++ return this.noiseBiomeSource.getNoiseBiome(x1, y1, z1); ++ // Leaf end - Carpet-Fixes - Optimized getBiome method ++ } + // Leaf end - cache getBiome + public Holder getBiome(BlockPos pos) { // Leaf start - Carpet-Fixes - Optimized getBiome method int xMinus2 = pos.getX() - 2; -@@ -126,9 +173,18 @@ public class BiomeManager { +@@ -126,9 +238,18 @@ public class BiomeManager { return Mth.square(zNoise + fiddle2) + Mth.square(yNoise + fiddle1) + Mth.square(xNoise + fiddle); } diff --git a/leaf-server/minecraft-patches/features/0262-optimize-mob-spawning.patch b/leaf-server/minecraft-patches/features/0262-optimize-mob-spawning.patch index e449a90e..2169e367 100644 --- a/leaf-server/minecraft-patches/features/0262-optimize-mob-spawning.patch +++ b/leaf-server/minecraft-patches/features/0262-optimize-mob-spawning.patch @@ -3,21 +3,30 @@ From: hayanesuru Date: Tue, 3 Jun 2025 15:20:59 +0900 Subject: [PATCH] optimize mob spawning +Avoid getChunk calls if its position is same as the chunk used for mob spawning + +Fix data race in async mob spawning +by adding chunk position to the mob count map +then apply result on server thread. + +Generally faster than the non-async approach + +iterate over all entities, get their chunk, and increment the count diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java -index 79674f4bd7a12c42dec19a4175012d7a2dc88b84..9f4ba5b7e054bbe70a820068f22fe8a6b9d72554 100644 +index 79674f4bd7a12c42dec19a4175012d7a2dc88b84..0a97a491737807d59815b75635fa3d8c94901ba8 100644 --- a/net/minecraft/server/level/ChunkMap.java +++ b/net/minecraft/server/level/ChunkMap.java @@ -287,6 +287,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider } // Paper end - per player mob count backoff public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) { -+ // Leaf - diff - fixme: not available in /paper playermobcaps with async mob spawning ++ // Leaf - diff - async mob spawning - optimize mob spawning return player.mobCounts[mobCategory.ordinal()] + player.mobBackoffCounts[mobCategory.ordinal()]; // Paper - per player mob count backoff } // Paper end - Optional per player mob spawns diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 46e171ca454253c32e22c0c18587e9a7ba19f331..1c23d82a2034bc4ae61ee9bc6c74b39940d4fc2b 100644 +index 46e171ca454253c32e22c0c18587e9a7ba19f331..d91d6988268174ea9f2c919b57a6ba7ea00d7066 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -70,11 +70,11 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon @@ -34,7 +43,59 @@ index 46e171ca454253c32e22c0c18587e9a7ba19f331..1c23d82a2034bc4ae61ee9bc6c74b399 // Paper start public final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>(); public int getFullChunksCount() { -@@ -542,10 +542,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -498,6 +498,23 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + } + + private void tickChunks() { ++ // Leaf start ++ if (org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled && this.level.tickRateManager().runsNormally()) { ++ for (ServerPlayer player : this.level.players) { ++ // Paper start - per player mob spawning backoff ++ for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) { ++ player.mobCounts[ii] = 0; ++ ++ int newBackoff = player.mobBackoffCounts[ii] - 1; // TODO make configurable bleed // TODO use nonlinear algorithm? ++ if (newBackoff < 0) { ++ newBackoff = 0; ++ } ++ player.mobBackoffCounts[ii] = newBackoff; ++ } ++ // Paper end - per player mob spawning backoff ++ } ++ } ++ // Leaf end + long gameTime = this.level.getGameTime(); + long l = gameTime - this.lastInhabitedUpdate; + this.lastInhabitedUpdate = gameTime; +@@ -511,8 +528,8 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + } + + // Pufferfish start - optimize mob spawning +- if (org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled) { +- for (ServerPlayer player : this.level.players) { ++ if (org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled && this.level.tickRateManager().runsNormally()) { ++ /*for (ServerPlayer player : this.level.players) { + // Paper start - per player mob spawning backoff + for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) { + player.mobCounts[ii] = 0; +@@ -524,14 +541,14 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + player.mobBackoffCounts[ii] = newBackoff; + } + // Paper end - per player mob spawning backoff +- } ++ }*/ + if (firstRunSpawnCounts) { + firstRunSpawnCounts = false; + _pufferfish_spawnCountsReady.set(true); + } + if (_pufferfish_spawnCountsReady.getAndSet(false)) { ++ int mapped = distanceManager.getNaturalSpawnChunkCount(); + net.minecraft.server.MinecraftServer.getServer().mobSpawnExecutor.submit(() -> { +- int mapped = distanceManager.getNaturalSpawnChunkCount(); + ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.Iterator objectiterator = + level.entityTickList.entities.iterator(ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS); + try { +@@ -542,10 +559,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon new LocalMobCapCalculator(chunkMap) : null; // This ensures the caps are properly enforced by using the correct calculator @@ -47,7 +108,7 @@ index 46e171ca454253c32e22c0c18587e9a7ba19f331..1c23d82a2034bc4ae61ee9bc6c74b399 mobCapCalculator, // This is the key fix - was previously null level.paperConfig().entities.spawning.perPlayerMobSpawns ); -@@ -627,9 +627,23 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -627,9 +644,23 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled // Paper end - chunk tick iteration optimisation @@ -74,7 +135,7 @@ index 46e171ca454253c32e22c0c18587e9a7ba19f331..1c23d82a2034bc4ae61ee9bc6c74b399 list.clear(); } diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java -index f242941ce06d356a025e306efe78c688e9b755c4..5e4cea207d5a5b12d45cf73d59d254e775a7db1a 100644 +index 81e176d17fb072f9ee531639abfe42134ae833a9..ab6fa7ed111ef16a0b6774c21988589ee2110c66 100644 --- a/net/minecraft/world/level/NaturalSpawner.java +++ b/net/minecraft/world/level/NaturalSpawner.java @@ -68,6 +68,7 @@ public final class NaturalSpawner { @@ -305,7 +366,7 @@ index f242941ce06d356a025e306efe78c688e9b755c4..5e4cea207d5a5b12d45cf73d59d254e7 + private static Optional getRandomSpawnMobAtWithChunk( + ServerLevel level, StructureManager structureManager, ChunkGenerator generator, MobCategory category, RandomSource random, BlockPos pos, LevelChunk chunk + ) { -+ Holder biome = org.dreeam.leaf.config.modules.opt.OptimizeBiome.mobSpawn ? level.getBiomeCached(pos) : level.getBiome(pos); // Leaf - cache getBiome ++ Holder biome = org.dreeam.leaf.config.modules.opt.OptimizeBiome.mobSpawn ? level.getBiomeCached(chunk, pos) : level.getBiome(pos); // Leaf - cache getBiome + return category == MobCategory.WATER_AMBIENT && biome.is(BiomeTags.REDUCED_WATER_AMBIENT_SPAWNS) && random.nextFloat() < 0.98F + ? Optional.empty() + : mobsAtWithChunk(level, structureManager, generator, category, pos, biome, chunk).getRandom(random); @@ -316,7 +377,7 @@ index f242941ce06d356a025e306efe78c688e9b755c4..5e4cea207d5a5b12d45cf73d59d254e7 ServerLevel level, StructureManager structureManager, ChunkGenerator generator, MobCategory category, MobSpawnSettings.SpawnerData data, BlockPos pos ) { @@ -463,6 +612,16 @@ public final class NaturalSpawner { - : generator.getMobsAt(biome != null ? biome : (org.dreeam.leaf.config.modules.opt.OptimizeBiome.mobSpawn ? level.getBiomeCached(pos) : level.getBiome(pos)), structureManager, cetagory, pos); // Leaf - cache getBiome + : 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 } + // Leaf start - optimize mob spawning @@ -325,14 +386,14 @@ index f242941ce06d356a025e306efe78c688e9b755c4..5e4cea207d5a5b12d45cf73d59d254e7 + ) { + return isInNetherFortressBoundsChunk(pos, level, cetagory, structureManager, chunk) + ? NetherFortressStructure.FORTRESS_ENEMIES -+ : generator.getMobsAtChunk(biome != null ? biome : (org.dreeam.leaf.config.modules.opt.OptimizeBiome.mobSpawn ? level.getBiomeCached(pos) : level.getBiome(pos)), structureManager, cetagory, pos, chunk); // Leaf - cache getBiome ++ : generator.getMobsAtChunk(biome != null ? biome : (org.dreeam.leaf.config.modules.opt.OptimizeBiome.mobSpawn ? level.getBiomeCached(chunk, pos) : level.getBiome(pos)), structureManager, cetagory, pos, chunk); // Leaf - cache getBiome + } + // Leaf end - optimize mob spawning + public static boolean isInNetherFortressBounds(BlockPos pos, ServerLevel level, MobCategory category, StructureManager structureManager) { if (category == MobCategory.MONSTER && level.getBlockState(pos.below()).is(Blocks.NETHER_BRICKS)) { Structure structure = structureManager.registryAccess().lookupOrThrow(Registries.STRUCTURE).getValue(BuiltinStructures.FORTRESS); -@@ -472,6 +631,28 @@ public final class NaturalSpawner { +@@ -472,6 +631,17 @@ public final class NaturalSpawner { } } @@ -346,22 +407,11 @@ index f242941ce06d356a025e306efe78c688e9b755c4..5e4cea207d5a5b12d45cf73d59d254e7 + } + } + // Leaf end - optimize mob spawning -+ -+ // Leaf start - optimize mob spawning -+ private static void mutableRandomPosWithin(BlockPos.MutableBlockPos pos1, Level level, LevelChunk chunk) { -+ ChunkPos pos = chunk.getPos(); -+ int randomX = pos.getMinBlockX() + level.random.nextInt(16); -+ int randomZ = pos.getMinBlockZ() + level.random.nextInt(16); -+ int surfaceY = chunk.getHeight(Heightmap.Types.WORLD_SURFACE, randomX, randomZ) + 1; -+ int randomY = Mth.randomBetweenInclusive(level.random, level.getMinY(), surfaceY); -+ pos1.set(randomX, randomY, randomZ); -+ } -+ // Leaf end - optimize mob spawning + private static BlockPos getRandomPosWithin(Level level, LevelChunk chunk) { ChunkPos pos = chunk.getPos(); int i = pos.getMinBlockX() + level.random.nextInt(16); -@@ -612,18 +793,21 @@ public final class NaturalSpawner { +@@ -612,18 +782,21 @@ public final class NaturalSpawner { @Nullable private EntityType lastCheckedType; private double lastCharge; @@ -384,7 +434,7 @@ index f242941ce06d356a025e306efe78c688e9b755c4..5e4cea207d5a5b12d45cf73d59d254e7 } private boolean canSpawn(EntityType entityType, BlockPos pos, ChunkAccess chunk) { -@@ -680,5 +864,32 @@ public final class NaturalSpawner { +@@ -680,5 +853,32 @@ public final class NaturalSpawner { boolean canSpawnForCategoryLocal(MobCategory category, ChunkPos chunkPos) { return this.localMobCapCalculator.canSpawn(category, chunkPos); } @@ -418,10 +468,18 @@ index f242941ce06d356a025e306efe78c688e9b755c4..5e4cea207d5a5b12d45cf73d59d254e7 } } diff --git a/net/minecraft/world/level/StructureManager.java b/net/minecraft/world/level/StructureManager.java -index fbe93098ce0366054a6da857cd808af1431b6612..27a0d52f75f7356dfd9e680dd97c3a9ce87304c6 100644 +index fbe93098ce0366054a6da857cd808af1431b6612..57de70773d2766a8f3a41e61efc16ceb7a9f80c8 100644 --- a/net/minecraft/world/level/StructureManager.java +++ b/net/minecraft/world/level/StructureManager.java -@@ -181,6 +181,12 @@ public class StructureManager { +@@ -90,6 +90,7 @@ public class StructureManager { + + @Nullable + public StructureStart getStartForStructure(SectionPos sectionPos, Structure structure, StructureAccess structureAccess) { ++ // Leaf - optimize mob spawning - diff + return structureAccess.getStartForStructure(structure); + } + +@@ -181,6 +182,12 @@ public class StructureManager { //SectionPos sectionPos = SectionPos.of(pos); // Leaf - optimise ChunkGenerator#getMobsAt return this.level.getChunk(pos.getX() >> 4, pos.getZ() >> 4, ChunkStatus.STRUCTURE_REFERENCES).getAllReferences(); // Leaf - optimise ChunkGenerator#getMobsAt } @@ -448,7 +506,7 @@ index db3b8a237d63255aa9ffd70c88a093002a6bd770..4a69f404eee00d8972e9501a76031d43 } diff --git a/net/minecraft/world/level/chunk/ChunkGenerator.java b/net/minecraft/world/level/chunk/ChunkGenerator.java -index 11c7c299d4affb9e78488590e7db939efe6e3dd9..94192345a732f0341886f44d90f9b979ca1fa780 100644 +index 11c7c299d4affb9e78488590e7db939efe6e3dd9..f1675db9942751235bb31634d5b99fdc30fb2950 100644 --- a/net/minecraft/world/level/chunk/ChunkGenerator.java +++ b/net/minecraft/world/level/chunk/ChunkGenerator.java @@ -516,6 +516,35 @@ public abstract class ChunkGenerator { @@ -466,7 +524,7 @@ index 11c7c299d4affb9e78488590e7db939efe6e3dd9..94192345a732f0341886f44d90f9b979 + // Leaf start - optimise ChunkGenerator#getMobsAt + for (long l : entry.getValue()) { + StructureStart startForStructure = structureManager.getStartForStructure( -+ null, structure, structureManager.level.getChunk(ChunkPos.getX(l), ChunkPos.getZ(l), ChunkStatus.STRUCTURE_STARTS) ++ null, structure, chunk.getPos().longKey == l ? chunk : structureManager.level.getChunk(ChunkPos.getX(l), ChunkPos.getZ(l), ChunkStatus.STRUCTURE_STARTS) + ); + if (startForStructure != null && startForStructure.isValid()) { + if (structureSpawnOverride.boundingBox() == StructureSpawnOverride.BoundingBoxType.PIECE diff --git a/leaf-server/minecraft-patches/features/0269-optimize-random-tick.patch b/leaf-server/minecraft-patches/features/0269-optimize-random-tick.patch index d6612f15..3fcb38cd 100644 --- a/leaf-server/minecraft-patches/features/0269-optimize-random-tick.patch +++ b/leaf-server/minecraft-patches/features/0269-optimize-random-tick.patch @@ -5,10 +5,10 @@ Subject: [PATCH] optimize random tick diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 1c23d82a2034bc4ae61ee9bc6c74b39940d4fc2b..57f45e571b92ff0b4499a97da33c8be746d8abd5 100644 +index d91d6988268174ea9f2c919b57a6ba7ea00d7066..804ad5ae82b875d3b2cccb828eaa0ea54fe43011 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java -@@ -648,7 +648,13 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -665,7 +665,13 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon list.clear(); } diff --git a/leaf-server/minecraft-patches/features/0272-Paw-optimization.patch b/leaf-server/minecraft-patches/features/0272-Paw-optimization.patch index 7d75195f..0b6999ff 100644 --- a/leaf-server/minecraft-patches/features/0272-Paw-optimization.patch +++ b/leaf-server/minecraft-patches/features/0272-Paw-optimization.patch @@ -100,10 +100,10 @@ index 4535858701b2bb232b9d2feb2af6551526232ddc..e65c62dbe4c1560ae153e4c4344e9194 - // Paper end - detailed watchdog information } diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 57f45e571b92ff0b4499a97da33c8be746d8abd5..c510dac9483d8e44118a29f5312e9876a9211e4e 100644 +index 804ad5ae82b875d3b2cccb828eaa0ea54fe43011..328ed610f5d532784bd6c38c4833591dc19442cb 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java -@@ -623,8 +623,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -640,8 +640,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon try { this.chunkMap.collectSpawningChunks(list); // Paper start - chunk tick iteration optimisation @@ -117,7 +117,7 @@ index 57f45e571b92ff0b4499a97da33c8be746d8abd5..c510dac9483d8e44118a29f5312e9876 // Leaf start - optimize mob spawning diff --git a/net/minecraft/server/level/ServerLevel.java b/net/minecraft/server/level/ServerLevel.java -index 35fb0770eb385e3837cb29711905c41b899bac8f..fd6fe51ccac5163e70569484239bebeb79348501 100644 +index d34a7cfa3b923d59ade35ce4c43cfd3f1477e057..e5ec54af005eb53399f9d2db49917c24023fcfdc 100644 --- a/net/minecraft/server/level/ServerLevel.java +++ b/net/minecraft/server/level/ServerLevel.java @@ -1517,13 +1517,7 @@ public class ServerLevel extends Level implements ServerEntityGetter, WorldGenLe diff --git a/leaf-server/paper-patches/features/0055-cache-getBiome.patch b/leaf-server/paper-patches/features/0055-cache-getBiome.patch index 9ef4307b..8b14ac78 100644 --- a/leaf-server/paper-patches/features/0055-cache-getBiome.patch +++ b/leaf-server/paper-patches/features/0055-cache-getBiome.patch @@ -5,7 +5,7 @@ Subject: [PATCH] cache getBiome diff --git a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java -index 0e14f962b26823e49b192a4f97ec6c1f477ef0ff..cb6cd899fd8af069534f45a4a9e81137f941e250 100644 +index 0e14f962b26823e49b192a4f97ec6c1f477ef0ff..757dd75474b134be8e432d64e1c11d52ecbb0587 100644 --- a/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java +++ b/src/main/java/org/bukkit/craftbukkit/util/DelegatedGeneratorAccess.java @@ -285,6 +285,13 @@ public abstract class DelegatedGeneratorAccess implements WorldGenLevel { @@ -14,8 +14,8 @@ index 0e14f962b26823e49b192a4f97ec6c1f477ef0ff..cb6cd899fd8af069534f45a4a9e81137 + // Leaf start - cache getBiome + @Override -+ public Holder getBiomeCached(BlockPos pos) { -+ return this.delegate.getBiomeCached(pos); ++ public Holder getBiomeCached(@Nullable net.minecraft.world.level.chunk.LevelChunk chunk, BlockPos pos) { ++ return this.delegate.getBiomeCached(chunk, pos); + } + // Leaf end - cache getBiome +