diff --git a/leaf-server/minecraft-patches/features/0184-optimise-getBiome.patch b/leaf-server/minecraft-patches/features/0184-optimise-getBiome.patch index 4eaf4697..bd1a671c 100644 --- a/leaf-server/minecraft-patches/features/0184-optimise-getBiome.patch +++ b/leaf-server/minecraft-patches/features/0184-optimise-getBiome.patch @@ -5,7 +5,7 @@ Subject: [PATCH] optimise getBiome diff --git a/net/minecraft/advancements/critereon/LocationPredicate.java b/net/minecraft/advancements/critereon/LocationPredicate.java -index a26a5311f87873e0d4d26fda9cb8956a32ee81e8..9405f1f211db3fa2d313429866de454ede64d95b 100644 +index a26a5311f87873e0d4d26fda9cb8956a32ee81e8..65e4315cce35814c60b21bbd5baea2ffac82162c 100644 --- a/net/minecraft/advancements/critereon/LocationPredicate.java +++ b/net/minecraft/advancements/critereon/LocationPredicate.java @@ -49,7 +49,7 @@ public record LocationPredicate( @@ -13,7 +13,7 @@ index a26a5311f87873e0d4d26fda9cb8956a32ee81e8..9405f1f211db3fa2d313429866de454e 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(level.getBiomeCached(blockPos))) // Leaf - cache getBiome ++ 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 && (!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)) @@ -35,7 +35,7 @@ index 26c8c1e5598daf3550aef05b12218c47bda6618b..91b2fc5b2da6566b05fef1111665b895 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 ce2621a87dec1befb016b3437ceb2d02ed6d0b75..c0d941af10ffe8c158dab9db40c7c5767b6cfd6e 100644 +index ce2621a87dec1befb016b3437ceb2d02ed6d0b75..9b37b763c6555705f3e256010f508b5a0c2cdb66 100644 --- a/net/minecraft/world/level/NaturalSpawner.java +++ b/net/minecraft/world/level/NaturalSpawner.java @@ -445,7 +445,7 @@ public final class NaturalSpawner { @@ -43,7 +43,7 @@ index ce2621a87dec1befb016b3437ceb2d02ed6d0b75..c0d941af10ffe8c158dab9db40c7c576 ServerLevel level, StructureManager structureManager, ChunkGenerator generator, MobCategory category, RandomSource random, BlockPos pos ) { - Holder biome = level.getBiome(pos); -+ Holder biome = level.getBiomeCached(pos); // Leaf - cache getBiome ++ Holder biome = org.dreeam.leaf.config.modules.opt.OptimizeBiome.mobSpawn ? level.getBiomeCached(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,7 +52,7 @@ index ce2621a87dec1befb016b3437ceb2d02ed6d0b75..c0d941af10ffe8c158dab9db40c7c576 return isInNetherFortressBounds(pos, level, category, structureManager) ? NetherFortressStructure.FORTRESS_ENEMIES - : generator.getMobsAt(biome != null ? biome : level.getBiome(pos), structureManager, category, pos); -+ : generator.getMobsAt(biome != null ? biome : level.getBiomeCached(pos), structureManager, category, pos); // Leaf - cache getBiome ++ : generator.getMobsAt(biome != null ? biome : (org.dreeam.leaf.config.modules.opt.OptimizeBiome.mobSpawn ? level.getBiomeCached(pos) : level.getBiome(pos)), structureManager, category, pos); // Leaf - cache getBiome } public static boolean isInNetherFortressBounds(BlockPos pos, ServerLevel level, MobCategory category, StructureManager structureManager) { diff --git a/leaf-server/minecraft-patches/features/0185-optimise-NaturalSpawner-spawnForChunk.patch b/leaf-server/minecraft-patches/features/0185-optimize-mob-spawning.patch similarity index 53% rename from leaf-server/minecraft-patches/features/0185-optimise-NaturalSpawner-spawnForChunk.patch rename to leaf-server/minecraft-patches/features/0185-optimize-mob-spawning.patch index 6601e40d..c4f91deb 100644 --- a/leaf-server/minecraft-patches/features/0185-optimise-NaturalSpawner-spawnForChunk.patch +++ b/leaf-server/minecraft-patches/features/0185-optimize-mob-spawning.patch @@ -1,14 +1,95 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: hayanesuru Date: Tue, 3 Jun 2025 15:20:59 +0900 -Subject: [PATCH] optimise NaturalSpawner#spawnForChunk +Subject: [PATCH] optimize mob spawning +diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java +index d61da0fbe7f6c181e4084ce60bfe7dab86f361ad..1ce1b21a77cd727b52bd937b65ce97517fed9c68 100644 +--- a/net/minecraft/server/level/ServerChunkCache.java ++++ b/net/minecraft/server/level/ServerChunkCache.java +@@ -70,7 +70,9 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + private final Set chunkHoldersToBroadcast = new ReferenceOpenHashSet<>(); + @Nullable + @VisibleForDebug +- private NaturalSpawner.SpawnState lastSpawnState; ++ private volatile NaturalSpawner.SpawnState lastSpawnState; // Leaf ++ private long delayTimeInhabited = 0L; // Leaf ++ private long delaySpawn = -1L; // Leaf + // Paper start + private final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>(); + public int getFullChunksCount() { +@@ -656,13 +658,37 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon + filteredSpawningCategories = List.of(); + } + +- for (LevelChunk levelChunk : chunks) { +- ChunkPos pos = levelChunk.getPos(); +- levelChunk.incrementInhabitedTime(timeInhabited); +- if (!filteredSpawningCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && lastSpawnState != null && (!org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled || _pufferfish_spawnCountsReady.get()) && this.chunkMap.anyPlayerCloseEnoughForSpawning(pos, true)) { // Spigot // Pufferfish // Leaf - Don't spawn if lastSpawnState is null +- NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState, filteredSpawningCategories); // Pufferfish ++ // Leaf start ++ var lastSpawnState1 = this.lastSpawnState; ++ if (lastSpawnState1 != null && (!org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled || _pufferfish_spawnCountsReady.get())) { ++ long sumTimeInhabited = timeInhabited + delayTimeInhabited; ++ long time = level.getGameTime(); ++ for (LevelChunk levelChunk : chunks) { ++ ChunkPos pos = levelChunk.getPos(); ++ levelChunk.incrementInhabitedTime(sumTimeInhabited); ++ if (!filteredSpawningCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && this.chunkMap.anyPlayerCloseEnoughForSpawning(pos, true)) { // Spigot ++ NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState1, filteredSpawningCategories, time); // Pufferfish ++ } ++ } ++ if (delaySpawn != -1L) { ++ time = delaySpawn; ++ for (LevelChunk levelChunk : chunks) { ++ ChunkPos pos = levelChunk.getPos(); ++ if (!filteredSpawningCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && this.chunkMap.anyPlayerCloseEnoughForSpawning(pos, true)) { // Spigot ++ NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState1, filteredSpawningCategories, time); // Pufferfish ++ } ++ } + } ++ delaySpawn = -1L; ++ delayTimeInhabited = 0L; ++ } else { ++ // unlikely ++ delayTimeInhabited += timeInhabited; ++ delaySpawn = level.getGameTime(); ++ } ++ // Leaf end + ++ for (LevelChunk levelChunk : chunks) { // Leaf - split to 2 loop + if (true) { // Paper - rewrite chunk system + this.level.tickChunk(levelChunk, _int); + } diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java -index c0d941af10ffe8c158dab9db40c7c5767b6cfd6e..450f17badaa3f6c8f1cdb9e6dc76828b70afe6fc 100644 +index 9b37b763c6555705f3e256010f508b5a0c2cdb66..7bfc636fb442036f742903c4e69a8a9fcd0e6fc2 100644 --- a/net/minecraft/world/level/NaturalSpawner.java +++ b/net/minecraft/world/level/NaturalSpawner.java -@@ -238,10 +238,13 @@ public final class NaturalSpawner { +@@ -155,7 +155,13 @@ public final class NaturalSpawner { + return list; + } + ++ @Deprecated(forRemoval = true) // Leaf + public static void spawnForChunk(ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnState spawnState, List categories) { ++ // Leaf start ++ spawnForChunk(level, chunk, spawnState, categories, level.getGameTime()); ++ } ++ public static void spawnForChunk(ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnState spawnState, List categories, long gameTime) { ++ // Leaf end + for (MobCategory mobCategory : categories) { + // Paper start - Optional per player mob spawns + final boolean canSpawn; +@@ -174,7 +180,7 @@ public final class NaturalSpawner { + } + // Paper end - throttle failed spawn attempts + if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { +- spawnThisTick = ticksPerSpawnTmp != 0 && level.getGameTime() % ticksPerSpawn == 0; // Paper - throttle failed spawn attempts ++ spawnThisTick = ticksPerSpawnTmp != 0 && gameTime % ticksPerSpawn == 0; // Paper - throttle failed spawn attempts // Leaf + limit = level.getWorld().getSpawnLimit(spawnCategory); + } + +@@ -238,12 +244,14 @@ public final class NaturalSpawner { // Paper end - throttle failed spawn attempts ) { // Paper end - Optional per player mob spawns @@ -18,27 +99,24 @@ index c0d941af10ffe8c158dab9db40c7c5767b6cfd6e..450f17badaa3f6c8f1cdb9e6dc76828b + // Leaf start + BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); + mutableRandomPosWithin(pos, level, chunk); -+ if (pos.getY() >= level.getMinY() + 1) { -+ return spawnCategoryForPosition(category, level, chunk, pos, filter, callback, maxSpawns, trackEntity, false); // Paper - Optional per player mob spawns // Paper - throttle failed spawn attempts ++ if (pos.getY() < level.getMinY() + 1) { ++ return 0; } +- +- return 0; // Paper - throttle failed spawn attempts ++ return spawnCategoryForPosition(category, level, chunk, pos, filter, callback, maxSpawns, trackEntity, false); // Paper - Optional per player mob spawns // Paper - throttle failed spawn attempts + // Leaf end - - return 0; // Paper - throttle failed spawn attempts } -@@ -275,31 +278,60 @@ public final class NaturalSpawner { + + @VisibleForDebug +@@ -275,31 +283,55 @@ public final class NaturalSpawner { StructureManager structureManager = level.structureManager(); ChunkGenerator generator = level.getChunkSource().getGenerator(); int y = pos.getY(); + int posX = pos.getX(); // Leaf + int posZ = pos.getZ(); // Leaf int i = 0; // Paper - throttle failed spawn attempts -- BlockState blockState = level.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn -+ // Leaf start -+ if (!level.getWorldBorder().isWithinBounds(pos) || level.isOutsideBuildHeight(pos)) { -+ return i; -+ } -+ BlockState blockState = chunk.getPos().longKey == ChunkPos.asLong(pos) ? chunk.getBlockState(posX, y, posZ) : level.getBlockStateIfLoaded(pos); -+ // Leaf end + BlockState blockState = level.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn if (blockState != null && !blockState.isRedstoneConductor(chunk, pos)) { // Paper - don't load chunks for mob spawn - BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos(); + BlockPos.MutableBlockPos mutableBlockPos = pos instanceof BlockPos.MutableBlockPos pos2 ? pos2 : new BlockPos.MutableBlockPos(); // Leaf diff --git a/leaf-server/minecraft-patches/features/0187-throttle-mob-spawning.patch b/leaf-server/minecraft-patches/features/0187-throttle-mob-spawning.patch index 171c3123..d4079d19 100644 --- a/leaf-server/minecraft-patches/features/0187-throttle-mob-spawning.patch +++ b/leaf-server/minecraft-patches/features/0187-throttle-mob-spawning.patch @@ -1,21 +1,21 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: hayanesuru -Date: Tue, 3 Jun 2025 21:34:25 +0900 +Date: Wed, 4 Jun 2025 20:54:03 +0900 Subject: [PATCH] throttle mob spawning diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java -index 450f17badaa3f6c8f1cdb9e6dc76828b70afe6fc..2f709cca7180e2f4874a7f80ed32498aba6dcac0 100644 +index 7bfc636fb442036f742903c4e69a8a9fcd0e6fc2..762bdf1fe19546f89d34b9efdad66b00dab80006 100644 --- a/net/minecraft/world/level/NaturalSpawner.java +++ b/net/minecraft/world/level/NaturalSpawner.java -@@ -160,6 +160,17 @@ public final class NaturalSpawner { +@@ -166,6 +166,17 @@ public final class NaturalSpawner { // Paper start - Optional per player mob spawns final boolean canSpawn; int maxSpawns = Integer.MAX_VALUE; + // Leaf start -+ if (org.dreeam.leaf.config.modules.opt.ThrottleNaturalSpawnMob.enabled) { -+ int spawnChance = org.dreeam.leaf.config.modules.opt.ThrottleNaturalSpawnMob.spawnChance[mobCategory.ordinal()]; -+ long failedAttempt = org.dreeam.leaf.config.modules.opt.ThrottleNaturalSpawnMob.failedAttempts[mobCategory.ordinal()]; ++ if (org.dreeam.leaf.config.modules.opt.ThrottleNaturalMobSpawning.enabled) { ++ int spawnChance = org.dreeam.leaf.config.modules.opt.ThrottleNaturalMobSpawning.spawnChance[mobCategory.ordinal()]; ++ long failedAttempt = org.dreeam.leaf.config.modules.opt.ThrottleNaturalMobSpawning.failedAttempts[mobCategory.ordinal()]; + if (failedAttempt >= 0L + && chunk.failedSpawnAttempts[mobCategory.ordinal()] >= failedAttempt + && (level.random.nextInt() & 1023) > spawnChance) { diff --git a/leaf-server/minecraft-patches/features/0188-delay-to-next-tick-when-mob-spawning-not-ready.patch b/leaf-server/minecraft-patches/features/0188-delay-to-next-tick-when-mob-spawning-not-ready.patch deleted file mode 100644 index ce40d12e..00000000 --- a/leaf-server/minecraft-patches/features/0188-delay-to-next-tick-when-mob-spawning-not-ready.patch +++ /dev/null @@ -1,81 +0,0 @@ -From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: hayanesuru -Date: Wed, 4 Jun 2025 00:31:39 +0900 -Subject: [PATCH] delay to next tick when mob spawning not ready - - -diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index d61da0fbe7f6c181e4084ce60bfe7dab86f361ad..d9f74ac79e67ed7b9619041cce763b60a8f9a929 100644 ---- a/net/minecraft/server/level/ServerChunkCache.java -+++ b/net/minecraft/server/level/ServerChunkCache.java -@@ -70,7 +70,8 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon - private final Set chunkHoldersToBroadcast = new ReferenceOpenHashSet<>(); - @Nullable - @VisibleForDebug -- private NaturalSpawner.SpawnState lastSpawnState; -+ private volatile NaturalSpawner.SpawnState lastSpawnState; // Leaf -+ private final it.unimi.dsi.fastutil.longs.LongArrayList delaySpawn = new it.unimi.dsi.fastutil.longs.LongArrayList(); // Leaf - // Paper start - private final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>(); - public int getFullChunksCount() { -@@ -656,13 +657,30 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon - filteredSpawningCategories = List.of(); - } - -- for (LevelChunk levelChunk : chunks) { -- ChunkPos pos = levelChunk.getPos(); -- levelChunk.incrementInhabitedTime(timeInhabited); -- if (!filteredSpawningCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && lastSpawnState != null && (!org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled || _pufferfish_spawnCountsReady.get()) && this.chunkMap.anyPlayerCloseEnoughForSpawning(pos, true)) { // Spigot // Pufferfish // Leaf - Don't spawn if lastSpawnState is null -- NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState, filteredSpawningCategories); // Pufferfish -+ // Leaf start -+ var lastSpawnState1 = this.lastSpawnState; -+ if (lastSpawnState1 != null && (!org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled || _pufferfish_spawnCountsReady.get())) { -+ int delaySpawnSize = delaySpawn.size(); -+ for (LevelChunk levelChunk : chunks) { -+ ChunkPos pos = levelChunk.getPos(); -+ levelChunk.incrementInhabitedTime(timeInhabited); -+ if (!filteredSpawningCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && this.chunkMap.anyPlayerCloseEnoughForSpawning(pos, true)) { // Spigot -+ for (int i = 0; i < delaySpawnSize; i++) { -+ NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState1, filteredSpawningCategories, delaySpawn.getLong(i)); -+ } -+ NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState1, filteredSpawningCategories); // Pufferfish -+ } - } -+ delaySpawn.clear(); -+ } else { -+ for (LevelChunk levelChunk : chunks) { -+ levelChunk.incrementInhabitedTime(timeInhabited); -+ } -+ delaySpawn.add(level.getGameTime()); -+ } -+ // Leaf end - -+ for (LevelChunk levelChunk : chunks) { // Leaf - if (true) { // Paper - rewrite chunk system - this.level.tickChunk(levelChunk, _int); - } -diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java -index 2f709cca7180e2f4874a7f80ed32498aba6dcac0..32c9106b70ef7ab85077d6ec4bd7d7b84d9f8c00 100644 ---- a/net/minecraft/world/level/NaturalSpawner.java -+++ b/net/minecraft/world/level/NaturalSpawner.java -@@ -156,6 +156,11 @@ public final class NaturalSpawner { - } - - public static void spawnForChunk(ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnState spawnState, List categories) { -+ // Leaf start -+ spawnForChunk(level, chunk, spawnState, categories, level.getGameTime()); -+ } -+ public static void spawnForChunk(ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnState spawnState, List categories, long gameTime) { -+ // Leaf end - for (MobCategory mobCategory : categories) { - // Paper start - Optional per player mob spawns - final boolean canSpawn; -@@ -185,7 +190,7 @@ public final class NaturalSpawner { - } - // Paper end - throttle failed spawn attempts - if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { -- spawnThisTick = ticksPerSpawnTmp != 0 && level.getGameTime() % ticksPerSpawn == 0; // Paper - throttle failed spawn attempts -+ spawnThisTick = ticksPerSpawnTmp != 0 && gameTime % ticksPerSpawn == 0; // Paper - throttle failed spawn attempts // Leaf - limit = level.getWorld().getSpawnLimit(spawnCategory); - } - diff --git a/leaf-server/minecraft-patches/features/0188-preload-mob-spawning-position.patch b/leaf-server/minecraft-patches/features/0188-preload-mob-spawning-position.patch new file mode 100644 index 00000000..a48c0781 --- /dev/null +++ b/leaf-server/minecraft-patches/features/0188-preload-mob-spawning-position.patch @@ -0,0 +1,108 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: hayanesuru +Date: Wed, 4 Jun 2025 20:54:32 +0900 +Subject: [PATCH] preload mob spawning position + + +diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java +index 762bdf1fe19546f89d34b9efdad66b00dab80006..0443df34de4f940f64e563ea76453493cadf200b 100644 +--- a/net/minecraft/world/level/NaturalSpawner.java ++++ b/net/minecraft/world/level/NaturalSpawner.java +@@ -257,9 +257,56 @@ public final class NaturalSpawner { + // Paper end - Optional per player mob spawns + // Leaf start + BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos(); +- mutableRandomPosWithin(pos, level, chunk); +- if (pos.getY() < level.getMinY() + 1) { +- return 0; ++ // Leaf start ++ if (org.dreeam.leaf.config.modules.opt.PreloadNaturalMobSpawning.enabled) { ++ if (chunk.cacheSpawnPosIndex == 16 || chunk.cacheSpawnPosIndex == -1) { ++ if (chunk.cacheSpawnPos == null) { ++ chunk.cacheSpawnPos = new long[16]; ++ } ++ // cache friendly ++ for (int i = 0; i < 16; i++) { ++ mutableRandomPosWithin(pos, level, chunk); ++ if (pos.getY() >= level.getMinY() + 1 ++ && level.getWorldBorder().isWithinBounds(pos) ++ && !level.isOutsideBuildHeight(pos)) { ++ LevelChunk chunk1 = chunk.getPos().longKey == ChunkPos.asLong(pos) ++ ? chunk ++ : level.chunkSource.getChunkAtIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4); ++ if (chunk1 != null) { ++ BlockState bs = chunk1.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ()); ++ if (bs != null && !bs.isRedstoneConductor(level, pos)) { ++ chunk.cacheSpawnPos[i] = BlockPos.asLong(pos.getX(), pos.getY(), pos.getZ()); ++ continue; ++ } ++ } ++ } ++ chunk.cacheSpawnPos[i] = -1; ++ } ++ chunk.cacheSpawnPosIndex = 0; ++ } ++ long cachePos = chunk.cacheSpawnPos[chunk.cacheSpawnPosIndex]; ++ chunk.cacheSpawnPosIndex++; ++ if (cachePos == -1) { ++ return 0; ++ } ++ pos.set(cachePos); ++ } else { ++ mutableRandomPosWithin(pos, level, chunk); ++ if (pos.getY() < level.getMinY() + 1 ++ || !level.getWorldBorder().isWithinBounds(pos) ++ || level.isOutsideBuildHeight(pos)) { ++ return 0; ++ } ++ LevelChunk chunk1 = chunk.getPos().longKey == ChunkPos.asLong(pos) ++ ? chunk ++ : level.chunkSource.getChunkAtIfLoadedImmediately(pos.getX() >> 4, pos.getZ() >> 4); ++ if (chunk1 == null) { ++ return 0; ++ } ++ BlockState bs = chunk1.getBlockStateFinal(pos.getX(), pos.getY(), pos.getZ()); ++ if (bs == null || bs.isRedstoneConductor(level, pos)) { ++ return 0; ++ } + } + return spawnCategoryForPosition(category, level, chunk, pos, filter, callback, maxSpawns, trackEntity, false); // Paper - Optional per player mob spawns // Paper - throttle failed spawn attempts + // Leaf end +@@ -284,7 +331,12 @@ public final class NaturalSpawner { + MobCategory category, ServerLevel level, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final @Nullable Consumer trackEntity + // Paper start - throttle failed spawn attempts + ) { +- spawnCategoryForPosition(category, level, chunk, pos, filter, callback, maxSpawns, trackEntity, false); ++ // Leaf start ++ BlockState blockState = level.getBlockStateIfLoadedAndInBounds(pos); ++ if (blockState != null && !blockState.isRedstoneConductor(chunk, pos)) { ++ spawnCategoryForPosition(category, level, chunk, pos, filter, callback, maxSpawns, trackEntity, false); ++ } ++ // Leaf end + } + public static int spawnCategoryForPosition( + MobCategory category, ServerLevel level, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final @Nullable Consumer trackEntity, final boolean nothing +@@ -297,8 +349,8 @@ public final class NaturalSpawner { + int posX = pos.getX(); // Leaf + int posZ = pos.getZ(); // Leaf + int i = 0; // Paper - throttle failed spawn attempts +- BlockState blockState = level.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn +- if (blockState != null && !blockState.isRedstoneConductor(chunk, pos)) { // Paper - don't load chunks for mob spawn ++ // BlockState blockState = level.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn // Leaf ++ if (true /*blockState != null && !blockState.isRedstoneConductor(chunk, pos)*/) { // Paper - don't load chunks for mob spawn // Leaf + BlockPos.MutableBlockPos mutableBlockPos = pos instanceof BlockPos.MutableBlockPos pos2 ? pos2 : new BlockPos.MutableBlockPos(); // Leaf + //int i = 0; // Paper - throttle failed spawn attempts - move up + +diff --git a/net/minecraft/world/level/chunk/LevelChunk.java b/net/minecraft/world/level/chunk/LevelChunk.java +index e6eab6929b08503c49debbbd25497ffedad438e1..624a177695580510c0a49d4503dee72da7fd7114 100644 +--- a/net/minecraft/world/level/chunk/LevelChunk.java ++++ b/net/minecraft/world/level/chunk/LevelChunk.java +@@ -106,6 +106,8 @@ public class LevelChunk extends ChunkAccess implements ca.spottedleaf.moonrise.p + // Paper start - rewrite chunk system + private boolean postProcessingDone; + private net.minecraft.server.level.ServerChunkCache.ChunkAndHolder chunkAndHolder; ++ public long[] cacheSpawnPos = null; // Leaf ++ public int cacheSpawnPosIndex = -1; // Leaf + + @Override + public final boolean moonrise$isPostProcessingDone() { diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizeBiome.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizeBiome.java index 3287f98c..27d2a9d3 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizeBiome.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/OptimizeBiome.java @@ -5,13 +5,17 @@ import org.dreeam.leaf.config.EnumConfigCategory; public class OptimizeBiome extends ConfigModules { public String getBasePath() { - return EnumConfigCategory.PERF.getBaseKeyName() + ".cache-mob-spawning-biome"; + return EnumConfigCategory.PERF.getBaseKeyName() + ".cache-biome"; } public static boolean enabled = false; + public static boolean mobSpawn = false; + public static boolean advancement = false; @Override public void onLoaded() { - enabled = config().getBoolean(getBasePath(), enabled); + enabled = config().getBoolean(getBasePath() + ".enabled", enabled); + mobSpawn = config.getBoolean(getBasePath() + ".mob-spawning", false); + advancement = config.getBoolean(getBasePath() + ".advancements", false); } } diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/PreloadNaturalMobSpawning.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/PreloadNaturalMobSpawning.java new file mode 100644 index 00000000..50a5742e --- /dev/null +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/PreloadNaturalMobSpawning.java @@ -0,0 +1,17 @@ +package org.dreeam.leaf.config.modules.opt; + +import org.dreeam.leaf.config.ConfigModules; +import org.dreeam.leaf.config.EnumConfigCategory; + +public class PreloadNaturalMobSpawning extends ConfigModules { + public String getBasePath() { + return EnumConfigCategory.PERF.getBaseKeyName() + ".preload-mob-spawning-position"; + } + + public static boolean enabled = false; + + @Override + public void onLoaded() { + enabled = config.getBoolean(getBasePath() + ".enabled", enabled); + } +} diff --git a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/ThrottleNaturalSpawnMob.java b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/ThrottleNaturalMobSpawning.java similarity index 91% rename from leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/ThrottleNaturalSpawnMob.java rename to leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/ThrottleNaturalMobSpawning.java index 73bb8eb7..8dbcff11 100644 --- a/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/ThrottleNaturalSpawnMob.java +++ b/leaf-server/src/main/java/org/dreeam/leaf/config/modules/opt/ThrottleNaturalMobSpawning.java @@ -4,9 +4,9 @@ import net.minecraft.world.entity.MobCategory; import org.dreeam.leaf.config.ConfigModules; import org.dreeam.leaf.config.EnumConfigCategory; -public class ThrottleNaturalSpawnMob extends ConfigModules { +public class ThrottleNaturalMobSpawning extends ConfigModules { public String getBasePath() { - return EnumConfigCategory.PERF.getBaseKeyName() + ".throttled-mob-spawning"; + return EnumConfigCategory.PERF.getBaseKeyName() + ".throttle-mob-spawning"; } public static boolean enabled = false; @@ -21,7 +21,7 @@ public class ThrottleNaturalSpawnMob extends ConfigModules { spawnChance = new int[categories.length]; for (int i = 0; i < categories.length; i++) { String category = getBasePath() + "." + categories[i].getSerializedName(); - long attempts = config.getLong(category + ".min-failed-attempts", 8); + long attempts = config.getLong(category + ".min-failed", 8); double chance = config.getDouble(category + ".spawn-chance", 25.0); failedAttempts[i] = Math.max(-1, attempts);