From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: NONPLAYT <76615486+NONPLAYT@users.noreply.github.com> Date: Wed, 19 Mar 2025 23:24:32 +0300 Subject: [PATCH] Async mob spawning diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java index 1a36a7c071c9f203d32f524008cf031fb1a4d6a6..c067f46935753794b49f29358262273fcd15d707 100644 --- a/net/minecraft/server/MinecraftServer.java +++ b/net/minecraft/server/MinecraftServer.java @@ -289,6 +289,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop S spin(Function threadFunction) { ca.spottedleaf.dataconverter.minecraft.datatypes.MCTypeRegistry.init(); // Paper - rewrite data converter system diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java index 2873642844c683ae4388ae27a045e01441d15426..adc2104447d738fd9f76d2e69690f0c76a41b844 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -182,6 +182,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } // Paper end - chunk tick iteration optimisations + // DivineMC start - Async mob spawning + public boolean firstRunSpawnCounts = true; + public final java.util.concurrent.atomic.AtomicBoolean spawnCountsReady = new java.util.concurrent.atomic.AtomicBoolean(false); + // DivineMC end - Async mob spawning public ServerChunkCache( ServerLevel level, @@ -505,6 +509,32 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon this.broadcastChangedChunks(); } + + // DivineMC start - Async mob spawning + if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) { + for (ServerPlayer player : this.level.players) { + for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) { + player.mobCounts[ii] = 0; + + int newBackoff = Math.max(0, player.mobBackoffCounts[ii] - 1); // DivineMC - Async mob spawning + player.mobBackoffCounts[ii] = newBackoff; + } + } + if (firstRunSpawnCounts) { + firstRunSpawnCounts = false; + spawnCountsReady.set(true); + } + if (spawnCountsReady.getAndSet(false)) { + MinecraftServer.getServer().mobSpawnExecutor.submit(() -> { + int mapped = distanceManager.getNaturalSpawnChunkCount(); + try { + lastSpawnState = NaturalSpawner.createState(mapped, new java.util.ArrayList<>(level.entityTickList.entities), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap), true); + } finally { } + spawnCountsReady.set(true); + }); + } + } + // DivineMC end - Async mob spawning } private void broadcastChangedChunks() { @@ -522,27 +552,31 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon int naturalSpawnChunkCount = this.distanceManager.getNaturalSpawnChunkCount(); // Paper start - Optional per player mob spawns NaturalSpawner.SpawnState spawnState; + // DivineMC start - Async mob spawning if ((this.spawnFriendlies || this.spawnEnemies) && this.level.paperConfig().entities.spawning.perPlayerMobSpawns) { // don't count mobs when animals and monsters are disabled - // re-set mob counts - 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; + if (!org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) { + // re-set mob counts + 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; } - player.mobBackoffCounts[ii] = newBackoff; + // Paper end - per player mob spawning backoff } - // Paper end - per player mob spawning backoff + lastSpawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap), true); } - spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true); } else { - spawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false); + lastSpawnState = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap), false); + spawnCountsReady.set(true); } + // DivineMC end - Async mob spawning // Paper end - Optional per player mob spawns - this.lastSpawnState = spawnState; boolean _boolean = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit int _int = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); List filteredSpawningCategories; @@ -556,7 +590,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon } // Paper end - PlayerNaturallySpawnCreaturesEvent boolean flag = this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && this.level.getLevelData().getGameTime() % this.level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit - filteredSpawningCategories = NaturalSpawner.getFilteredSpawningCategories(spawnState, this.spawnFriendlies, this.spawnEnemies, flag, this.level); // CraftBukkit + filteredSpawningCategories = NaturalSpawner.getFilteredSpawningCategories(lastSpawnState, this.spawnFriendlies, this.spawnEnemies, flag, this.level); // CraftBukkit // DivineMC - Async mob spawning } else { filteredSpawningCategories = List.of(); } @@ -571,7 +605,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon // Paper end - chunk tick iteration optimisation for (LevelChunk levelChunk : list) { - this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, spawnState); + this.tickSpawningChunk(levelChunk, timeInhabited, filteredSpawningCategories, lastSpawnState); // DivineMC - Async mob spawning } } finally { list.clear(); @@ -590,11 +624,11 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon this.level.tickThunder(chunk); } - if (!spawnCategories.isEmpty()) { - if (this.level.getWorldBorder().isWithinBounds(pos)) { // Paper - rewrite chunk system - NaturalSpawner.spawnForChunk(this.level, chunk, spawnState, spawnCategories); - } + // DivineMC start - Async mob spawning + if (!spawnCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && (!org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning || spawnCountsReady.get())) { // Paper - rewrite chunk system + NaturalSpawner.spawnForChunk(this.level, chunk, spawnState, spawnCategories); } + // DivineMC end - Async mob spawning } private void getFullChunk(long chunkPos, Consumer fullChunkGetter) { diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java index 68a074a1eb11b158af773a2c44aa49d5d8462080..a5f6f50ad1e276a908347d9c21527fb583734538 100644 --- a/net/minecraft/world/level/NaturalSpawner.java +++ b/net/minecraft/world/level/NaturalSpawner.java @@ -149,7 +149,18 @@ public final class NaturalSpawner { return list; } + private static int maxCapPerPlayer = -1; // DivineMC - Async mob spawning + public static void spawnForChunk(ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnState spawnState, List categories) { + // DivineMC start - Async mob spawning + if (maxCapPerPlayer < 0) { + maxCapPerPlayer = 0; + for (final MobCategory value : MobCategory.values()) { + maxCapPerPlayer += value.getMaxInstancesPerChunk(); + } + } + // DivineMC end - Async mob spawning + for (MobCategory mobCategory : categories) { // Paper start - Optional per player mob spawns final boolean canSpawn; @@ -680,6 +691,13 @@ public final class NaturalSpawner { } boolean canSpawnForCategoryLocal(MobCategory category, ChunkPos chunkPos) { + // DivineMC start - Async mob spawning + if (this.localMobCapCalculator == null) { + LOGGER.warn("Local mob cap calculator was null! Report to DivineMC!"); + return false; + } + // DivineMC end - Async mob spawning + return this.localMobCapCalculator.canSpawn(category, chunkPos); } } diff --git a/net/minecraft/world/level/entity/EntityTickList.java b/net/minecraft/world/level/entity/EntityTickList.java index c89701d7bdc9b889038d3c52f2232fb17624b113..9e75320e51886e0f93c23683d8614128f44a613e 100644 --- a/net/minecraft/world/level/entity/EntityTickList.java +++ b/net/minecraft/world/level/entity/EntityTickList.java @@ -9,7 +9,7 @@ import javax.annotation.Nullable; import net.minecraft.world.entity.Entity; public class EntityTickList { - public final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Paper - rewrite chunk system + public final java.util.concurrent.ConcurrentLinkedQueue entities = new java.util.concurrent.ConcurrentLinkedQueue<>(); // Paper - rewrite chunk system // DivineMC - Async mob spawning private void ensureActiveIsNotIterated() { // Paper - rewrite chunk system @@ -33,13 +33,13 @@ public class EntityTickList { // Paper start - rewrite chunk system // To ensure nothing weird happens with dimension travelling, do not iterate over new entries... // (by dfl iterator() is configured to not iterate over new entries) - final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.Iterator iterator = this.entities.iterator(); + final java.util.Iterator iterator = this.entities.iterator(); // DivineMC - Async mob spawning try { while (iterator.hasNext()) { entity.accept(iterator.next()); } } finally { - iterator.finishedIterating(); + //iterator.finishedIterating(); // DivineMC - Async mob spawning } // Paper end - rewrite chunk system }