From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: violetc <58360096+s-yh-china@users.noreply.github.com> Date: Fri, 21 Jul 2023 11:32:47 +0800 Subject: [PATCH] Skip unnecessary mob spawning computations This patch is Powered by Gale(https://github.com/GaleMC/Gale) diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java index 5942626173e68d80a2e93d7221f2f470f07f022b..82234b5a0288438cc1a0b8ca59c9a8e4e1a845b4 100644 --- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java +++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java @@ -566,50 +566,57 @@ public class ServerChunkCache extends ChunkSource { int k = this.level.getGameRules().getInt(GameRules.RULE_RANDOMTICKING); boolean flag1 = level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) != 0L && worlddata.getGameTime() % level.ticksPerSpawnCategory.getLong(org.bukkit.entity.SpawnCategory.ANIMAL) == 0L; // CraftBukkit - gameprofilerfiller.push("naturalSpawnCount"); - this.level.timings.countNaturalMobs.startTiming(); // Paper - timings - int l = this.distanceManager.getNaturalSpawnChunkCount(); - // Paper start - per player mob spawning + // Leaves start - skip unnecessary mob spawning computations NaturalSpawner.SpawnState spawnercreature_d; // moved down - if ((this.spawnFriendlies || this.spawnEnemies) && this.chunkMap.playerMobDistanceMap != null) { // don't count mobs when animals and monsters are disabled - // Leaves start - optimize mob spawning - if (!top.leavesmc.leaves.LeavesConfig.asyncMobSpawning) { - // 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; + boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit + boolean flag2AndHasNaturalSpawn = flag2 && this.anySpawnCategoryIsSpawnedThisTick(); + if (!top.leavesmc.leaves.LeavesConfig.skipUnnecessaryMobSpawningComputations || flag2AndHasNaturalSpawn) { + gameprofilerfiller.push("naturalSpawnCount"); + this.level.timings.countNaturalMobs.startTiming(); // Paper - timings + int l = this.distanceManager.getNaturalSpawnChunkCount(); + // Paper start - per player mob spawning + if ((this.spawnFriendlies || this.spawnEnemies) && this.chunkMap.playerMobDistanceMap != null) { // don't count mobs when animals and monsters are disabled + // Leaves start - optimize mob spawning + if (!top.leavesmc.leaves.LeavesConfig.asyncMobSpawning) { + //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(l, this.level.getAllEntities(), this::getFullChunk, null, true); } - lastSpawnState = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, null, true); + // Leaves end - optimize mob spawning + } else { + // Leaves start - optimize mob spawning + lastSpawnState = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, this.chunkMap.playerMobDistanceMap == null ? new LocalMobCapCalculator(this.chunkMap) : null, false); + spawnCountsReady.set(true); + // Leaves end - optimize mob spawning } - // Leaves end - optimize mob spawning + // Paper end + this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings + + // this.lastSpawnState = spawnercreature_d; // Leaves - optimize mob spawning + gameprofilerfiller.popPush("filteringLoadedChunks"); } else { - // Leaves start - optimize mob spawning - lastSpawnState = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, this.chunkMap.playerMobDistanceMap == null ? new LocalMobCapCalculator(this.chunkMap) : null, false); - spawnCountsReady.set(true); - // Leaves end - optimize mob spawning + spawnercreature_d = null; } - // Paper end - this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings - - // this.lastSpawnState = spawnercreature_d; // Leaves - optimize mob spawning - gameprofilerfiller.popPush("filteringLoadedChunks"); // Paper - moved down this.level.timings.chunkTicks.startTiming(); // Paper // Paper - moved down gameprofilerfiller.popPush("spawnAndTick"); - boolean flag2 = this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBSPAWNING) && !this.level.players().isEmpty(); // CraftBukkit + // Leaves start - skip unnecessary mob spawning computations // Paper - only shuffle if per-player mob spawning is disabled // Paper - moved natural spawn event up @@ -641,7 +648,7 @@ public class ServerChunkCache extends ChunkSource { if ((true || this.level.isNaturalSpawningAllowed(chunkcoordintpair)) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, false)) { // Paper - optimise anyPlayerCloseEnoughForSpawning // Paper - the chunk is known ticking chunk1.incrementInhabitedTime(j); // Leaves start - optimize mob spawning - if (flag2 && (!top.leavesmc.leaves.LeavesConfig.asyncMobSpawning || spawnCountsReady.get()) && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning & optimise chunk tick iteration + if ((top.leavesmc.leaves.LeavesConfig.skipUnnecessaryMobSpawningComputations ? flag2AndHasNaturalSpawn : flag2) && (!top.leavesmc.leaves.LeavesConfig.asyncMobSpawning || spawnCountsReady.get()) && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning & optimise chunk tick iteration // Leaves -skip unnecessary mob spawning computations NaturalSpawner.spawnForChunk(this.level, chunk1, lastSpawnState, this.spawnFriendlies, this.spawnEnemies, flag1); } // Leaves end - optimize mob spawning @@ -706,7 +713,7 @@ public class ServerChunkCache extends ChunkSource { // Paper end - controlled flush for entity tracker packets // Leaves start - optimize mob spawning - if (top.leavesmc.leaves.LeavesConfig.asyncMobSpawning) { + if (top.leavesmc.leaves.LeavesConfig.asyncMobSpawning && (!top.leavesmc.leaves.LeavesConfig.skipUnnecessaryMobSpawningComputations || flag2AndHasNaturalSpawn)) { for (ServerPlayer player : this.level.players) { for (int ii = 0; ii < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; ii++) { player.mobCounts[ii] = 0; @@ -739,6 +746,18 @@ public class ServerChunkCache extends ChunkSource { } } + // Leaves start - skip unnecessary mob spawning computations + public boolean anySpawnCategoryIsSpawnedThisTick() { + long gameTime = this.level.getLevelData().getGameTime(); + for (long ticksForSpawnCategory : this.level.ticksPerSpawnCategory.values()) { + if (ticksForSpawnCategory != 0L && gameTime % ticksForSpawnCategory == 0L) { + return true; + } + } + return false; + } + // Leaves stop - skip unnecessary mob spawning computations + private void getFullChunk(long pos, Consumer chunkConsumer) { ChunkHolder playerchunk = this.getVisibleChunkIfPresent(pos);