mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-23 17:09:29 +00:00
preload mob spawning position
This commit is contained in:
@@ -5,7 +5,7 @@ Subject: [PATCH] optimise getBiome
|
|||||||
|
|
||||||
|
|
||||||
diff --git a/net/minecraft/advancements/critereon/LocationPredicate.java b/net/minecraft/advancements/critereon/LocationPredicate.java
|
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
|
--- a/net/minecraft/advancements/critereon/LocationPredicate.java
|
||||||
+++ b/net/minecraft/advancements/critereon/LocationPredicate.java
|
+++ b/net/minecraft/advancements/critereon/LocationPredicate.java
|
||||||
@@ -49,7 +49,7 @@ public record LocationPredicate(
|
@@ -49,7 +49,7 @@ public record LocationPredicate(
|
||||||
@@ -13,7 +13,7 @@ index a26a5311f87873e0d4d26fda9cb8956a32ee81e8..9405f1f211db3fa2d313429866de454e
|
|||||||
BlockPos blockPos = BlockPos.containing(x, y, z);
|
BlockPos blockPos = BlockPos.containing(x, y, z);
|
||||||
boolean isLoaded = level.isLoaded(blockPos);
|
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.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.structures.isPresent() || isLoaded && level.structureManager().getStructureWithPieceAt(blockPos, this.structures.get()).isValid())
|
||||||
&& (!this.smokey.isPresent() || isLoaded && this.smokey.get() == CampfireBlock.isSmokeyPos(level, blockPos))
|
&& (!this.smokey.isPresent() || isLoaded && this.smokey.get() == CampfireBlock.isSmokeyPos(level, blockPos))
|
||||||
&& (!this.light.isPresent() || this.light.get().matches(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 floor = Mth.floor(aabb.minX);
|
||||||
int floor1 = Mth.floor(aabb.maxX);
|
int floor1 = Mth.floor(aabb.maxX);
|
||||||
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
|
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
|
--- a/net/minecraft/world/level/NaturalSpawner.java
|
||||||
+++ b/net/minecraft/world/level/NaturalSpawner.java
|
+++ b/net/minecraft/world/level/NaturalSpawner.java
|
||||||
@@ -445,7 +445,7 @@ public final class NaturalSpawner {
|
@@ -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
|
ServerLevel level, StructureManager structureManager, ChunkGenerator generator, MobCategory category, RandomSource random, BlockPos pos
|
||||||
) {
|
) {
|
||||||
- Holder<Biome> biome = level.getBiome(pos);
|
- Holder<Biome> biome = level.getBiome(pos);
|
||||||
+ Holder<Biome> biome = level.getBiomeCached(pos); // Leaf - cache getBiome
|
+ Holder<Biome> 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
|
return category == MobCategory.WATER_AMBIENT && biome.is(BiomeTags.REDUCED_WATER_AMBIENT_SPAWNS) && random.nextFloat() < 0.98F
|
||||||
? Optional.empty()
|
? Optional.empty()
|
||||||
: mobsAt(level, structureManager, generator, category, pos, biome).getRandom(random);
|
: mobsAt(level, structureManager, generator, category, pos, biome).getRandom(random);
|
||||||
@@ -52,7 +52,7 @@ index ce2621a87dec1befb016b3437ceb2d02ed6d0b75..c0d941af10ffe8c158dab9db40c7c576
|
|||||||
return isInNetherFortressBounds(pos, level, category, structureManager)
|
return isInNetherFortressBounds(pos, level, category, structureManager)
|
||||||
? NetherFortressStructure.FORTRESS_ENEMIES
|
? NetherFortressStructure.FORTRESS_ENEMIES
|
||||||
- : generator.getMobsAt(biome != null ? biome : level.getBiome(pos), structureManager, category, pos);
|
- : 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) {
|
public static boolean isInNetherFortressBounds(BlockPos pos, ServerLevel level, MobCategory category, StructureManager structureManager) {
|
||||||
|
|||||||
@@ -1,14 +1,95 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: hayanesuru <hayanesuru@outlook.jp>
|
From: hayanesuru <hayanesuru@outlook.jp>
|
||||||
Date: Tue, 3 Jun 2025 15:20:59 +0900
|
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<ChunkHolder> 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<net.minecraft.world.level.chunk.LevelChunk> 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
|
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
|
--- a/net/minecraft/world/level/NaturalSpawner.java
|
||||||
+++ b/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<MobCategory> categories) {
|
||||||
|
+ // Leaf start
|
||||||
|
+ spawnForChunk(level, chunk, spawnState, categories, level.getGameTime());
|
||||||
|
+ }
|
||||||
|
+ public static void spawnForChunk(ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnState spawnState, List<MobCategory> 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 - throttle failed spawn attempts
|
||||||
) {
|
) {
|
||||||
// Paper end - Optional per player mob spawns
|
// Paper end - Optional per player mob spawns
|
||||||
@@ -18,27 +99,24 @@ index c0d941af10ffe8c158dab9db40c7c5767b6cfd6e..450f17badaa3f6c8f1cdb9e6dc76828b
|
|||||||
+ // Leaf start
|
+ // Leaf start
|
||||||
+ BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
+ BlockPos.MutableBlockPos pos = new BlockPos.MutableBlockPos();
|
||||||
+ mutableRandomPosWithin(pos, level, chunk);
|
+ mutableRandomPosWithin(pos, level, chunk);
|
||||||
+ if (pos.getY() >= level.getMinY() + 1) {
|
+ 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
|
+ 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
|
+ // 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();
|
StructureManager structureManager = level.structureManager();
|
||||||
ChunkGenerator generator = level.getChunkSource().getGenerator();
|
ChunkGenerator generator = level.getChunkSource().getGenerator();
|
||||||
int y = pos.getY();
|
int y = pos.getY();
|
||||||
+ int posX = pos.getX(); // Leaf
|
+ int posX = pos.getX(); // Leaf
|
||||||
+ int posZ = pos.getZ(); // Leaf
|
+ int posZ = pos.getZ(); // Leaf
|
||||||
int i = 0; // Paper - throttle failed spawn attempts
|
int i = 0; // Paper - throttle failed spawn attempts
|
||||||
- BlockState blockState = level.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn
|
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
|
|
||||||
if (blockState != null && !blockState.isRedstoneConductor(chunk, 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 = new BlockPos.MutableBlockPos();
|
||||||
+ BlockPos.MutableBlockPos mutableBlockPos = pos instanceof BlockPos.MutableBlockPos pos2 ? pos2 : new BlockPos.MutableBlockPos(); // Leaf
|
+ BlockPos.MutableBlockPos mutableBlockPos = pos instanceof BlockPos.MutableBlockPos pos2 ? pos2 : new BlockPos.MutableBlockPos(); // Leaf
|
||||||
@@ -1,21 +1,21 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
From: hayanesuru <hayanesuru@outlook.jp>
|
From: hayanesuru <hayanesuru@outlook.jp>
|
||||||
Date: Tue, 3 Jun 2025 21:34:25 +0900
|
Date: Wed, 4 Jun 2025 20:54:03 +0900
|
||||||
Subject: [PATCH] throttle mob spawning
|
Subject: [PATCH] throttle mob spawning
|
||||||
|
|
||||||
|
|
||||||
diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java
|
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
|
--- a/net/minecraft/world/level/NaturalSpawner.java
|
||||||
+++ b/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
|
// Paper start - Optional per player mob spawns
|
||||||
final boolean canSpawn;
|
final boolean canSpawn;
|
||||||
int maxSpawns = Integer.MAX_VALUE;
|
int maxSpawns = Integer.MAX_VALUE;
|
||||||
+ // Leaf start
|
+ // Leaf start
|
||||||
+ if (org.dreeam.leaf.config.modules.opt.ThrottleNaturalSpawnMob.enabled) {
|
+ if (org.dreeam.leaf.config.modules.opt.ThrottleNaturalMobSpawning.enabled) {
|
||||||
+ int spawnChance = org.dreeam.leaf.config.modules.opt.ThrottleNaturalSpawnMob.spawnChance[mobCategory.ordinal()];
|
+ int spawnChance = org.dreeam.leaf.config.modules.opt.ThrottleNaturalMobSpawning.spawnChance[mobCategory.ordinal()];
|
||||||
+ long failedAttempt = org.dreeam.leaf.config.modules.opt.ThrottleNaturalSpawnMob.failedAttempts[mobCategory.ordinal()];
|
+ long failedAttempt = org.dreeam.leaf.config.modules.opt.ThrottleNaturalMobSpawning.failedAttempts[mobCategory.ordinal()];
|
||||||
+ if (failedAttempt >= 0L
|
+ if (failedAttempt >= 0L
|
||||||
+ && chunk.failedSpawnAttempts[mobCategory.ordinal()] >= failedAttempt
|
+ && chunk.failedSpawnAttempts[mobCategory.ordinal()] >= failedAttempt
|
||||||
+ && (level.random.nextInt() & 1023) > spawnChance) {
|
+ && (level.random.nextInt() & 1023) > spawnChance) {
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: hayanesuru <hayanesuru@outlook.jp>
|
|
||||||
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<ChunkHolder> 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<net.minecraft.world.level.chunk.LevelChunk> 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<MobCategory> categories) {
|
|
||||||
+ // Leaf start
|
|
||||||
+ spawnForChunk(level, chunk, spawnState, categories, level.getGameTime());
|
|
||||||
+ }
|
|
||||||
+ public static void spawnForChunk(ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnState spawnState, List<MobCategory> 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);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: hayanesuru <hayanesuru@outlook.jp>
|
||||||
|
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<Entity> 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<Entity> 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() {
|
||||||
@@ -5,13 +5,17 @@ import org.dreeam.leaf.config.EnumConfigCategory;
|
|||||||
|
|
||||||
public class OptimizeBiome extends ConfigModules {
|
public class OptimizeBiome extends ConfigModules {
|
||||||
public String getBasePath() {
|
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 enabled = false;
|
||||||
|
public static boolean mobSpawn = false;
|
||||||
|
public static boolean advancement = false;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onLoaded() {
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,9 +4,9 @@ import net.minecraft.world.entity.MobCategory;
|
|||||||
import org.dreeam.leaf.config.ConfigModules;
|
import org.dreeam.leaf.config.ConfigModules;
|
||||||
import org.dreeam.leaf.config.EnumConfigCategory;
|
import org.dreeam.leaf.config.EnumConfigCategory;
|
||||||
|
|
||||||
public class ThrottleNaturalSpawnMob extends ConfigModules {
|
public class ThrottleNaturalMobSpawning extends ConfigModules {
|
||||||
public String getBasePath() {
|
public String getBasePath() {
|
||||||
return EnumConfigCategory.PERF.getBaseKeyName() + ".throttled-mob-spawning";
|
return EnumConfigCategory.PERF.getBaseKeyName() + ".throttle-mob-spawning";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean enabled = false;
|
public static boolean enabled = false;
|
||||||
@@ -21,7 +21,7 @@ public class ThrottleNaturalSpawnMob extends ConfigModules {
|
|||||||
spawnChance = new int[categories.length];
|
spawnChance = new int[categories.length];
|
||||||
for (int i = 0; i < categories.length; i++) {
|
for (int i = 0; i < categories.length; i++) {
|
||||||
String category = getBasePath() + "." + categories[i].getSerializedName();
|
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);
|
double chance = config.getDouble(category + ".spawn-chance", 25.0);
|
||||||
|
|
||||||
failedAttempts[i] = Math.max(-1, attempts);
|
failedAttempts[i] = Math.max(-1, attempts);
|
||||||
Reference in New Issue
Block a user