mirror of
https://github.com/BX-Team/DivineMC.git
synced 2025-12-19 14:59:25 +00:00
179 lines
11 KiB
Diff
179 lines
11 KiB
Diff
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] Pufferfish: Optimize mob spawning
|
|
|
|
Original license: GPL v3
|
|
Original project: https://github.com/pufferfish-gg/Pufferfish
|
|
|
|
This patch reduces the main-thread impact of mob spawning by moving spawning work to other threads
|
|
|
|
diff --git a/net/minecraft/server/MinecraftServer.java b/net/minecraft/server/MinecraftServer.java
|
|
index 4ba10f90711ac8b6813f86bcff9635716fdc6028..95e39a728b7505a273a6e9c927308ee8931ea756 100644
|
|
--- a/net/minecraft/server/MinecraftServer.java
|
|
+++ b/net/minecraft/server/MinecraftServer.java
|
|
@@ -288,6 +288,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
|
|
public boolean lagging = false; // Purpur - Lagging threshold
|
|
protected boolean upnp = false; // Purpur - UPnP Port Forwarding
|
|
public final org.bxteam.divinemc.util.tps.TPSCalculator tpsCalculator = new org.bxteam.divinemc.util.tps.TPSCalculator(); // DivineMC - Lag compensation
|
|
+ public gg.pufferfish.pufferfish.util.AsyncExecutor mobSpawnExecutor = new gg.pufferfish.pufferfish.util.AsyncExecutor("Mob Spawning"); // DivineMC - Pufferfish: Optimize mob spawning
|
|
// Paper start - improve tick loop
|
|
public final ca.spottedleaf.moonrise.common.time.TickData tickTimes1s = new ca.spottedleaf.moonrise.common.time.TickData(java.util.concurrent.TimeUnit.SECONDS.toNanos(1L));
|
|
public final ca.spottedleaf.moonrise.common.time.TickData tickTimes5s = new ca.spottedleaf.moonrise.common.time.TickData(java.util.concurrent.TimeUnit.SECONDS.toNanos(5L));
|
|
diff --git a/net/minecraft/server/dedicated/DedicatedServer.java b/net/minecraft/server/dedicated/DedicatedServer.java
|
|
index f9ec63ed7feb67e558abed99746726c10e9e10f4..78f831bf369906396860a73b9aaff5dc67bcfa09 100644
|
|
--- a/net/minecraft/server/dedicated/DedicatedServer.java
|
|
+++ b/net/minecraft/server/dedicated/DedicatedServer.java
|
|
@@ -452,7 +452,7 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
|
|
|
|
org.purpurmc.purpur.task.BossBarTask.startAll(); // Purpur - Implement TPSBar
|
|
if (org.purpurmc.purpur.PurpurConfig.beeCountPayload) org.purpurmc.purpur.task.BeehiveTask.instance().register(); // Purpur - Give bee counts in beehives to Purpur clients
|
|
-
|
|
+ if (org.bxteam.divinemc.config.DivineConfig.AsyncCategory.enableAsyncSpawning) mobSpawnExecutor.start(); // DivineMC - Pufferfish: Optimize mob spawning
|
|
this.notificationManager().serverStarted();
|
|
return true;
|
|
}
|
|
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
|
index 65607de63f6ea900599660485861860b71e1aef3..0a32c1106d3eebb8b4aa75b27b489169052897db 100644
|
|
--- a/net/minecraft/server/level/ServerChunkCache.java
|
|
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
|
@@ -183,6 +183,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
}
|
|
// Paper end - chunk tick iteration optimisations
|
|
|
|
+ // DivineMC start - Pufferfish: Optimize mob spawning
|
|
+ public boolean firstRunSpawnCounts = true;
|
|
+ public final java.util.concurrent.atomic.AtomicBoolean spawnCountsReady = new java.util.concurrent.atomic.AtomicBoolean(false);
|
|
+ // DivineMC end - Pufferfish: Optimize mob spawning
|
|
|
|
public ServerChunkCache(
|
|
ServerLevel level,
|
|
@@ -501,6 +505,47 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
|
|
|
this.broadcastChangedChunks();
|
|
}
|
|
+
|
|
+ // DivineMC start - Pufferfish: Optimize 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);
|
|
+ player.mobBackoffCounts[ii] = newBackoff;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ if (firstRunSpawnCounts) {
|
|
+ firstRunSpawnCounts = false;
|
|
+ spawnCountsReady.set(true);
|
|
+ }
|
|
+
|
|
+ if (spawnCountsReady.getAndSet(false)) {
|
|
+ net.minecraft.server.MinecraftServer.getServer().mobSpawnExecutor.submit(() -> {
|
|
+ int mapped = distanceManager.getNaturalSpawnChunkCount();
|
|
+ ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.Iterator<Entity> objectiterator = level.entityTickList.entities.iterator(ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS);
|
|
+
|
|
+ try {
|
|
+ gg.pufferfish.pufferfish.util.IterableWrapper<Entity> wrappedIterator = new gg.pufferfish.pufferfish.util.IterableWrapper<>(objectiterator);
|
|
+ LocalMobCapCalculator mobCapCalculator = !level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(chunkMap) : null;
|
|
+
|
|
+ lastSpawnState = NaturalSpawner.createState(
|
|
+ mapped,
|
|
+ wrappedIterator,
|
|
+ ServerChunkCache.this::getFullChunk,
|
|
+ mobCapCalculator,
|
|
+ level.paperConfig().entities.spawning.perPlayerMobSpawns
|
|
+ );
|
|
+ } finally {
|
|
+ objectiterator.finishedIterating();
|
|
+ }
|
|
+ spawnCountsReady.set(true);
|
|
+ });
|
|
+ }
|
|
+ }
|
|
+ // DivineMC end - Pufferfish: Optimize mob spawning
|
|
}
|
|
|
|
private void broadcastChangedChunks() {
|
|
@@ -518,27 +563,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 - Pufferfish: Optimize 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 - Pufferfish: Optimize 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<MobCategory> filteredSpawningCategories;
|
|
@@ -552,7 +601,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 - Pufferfish: Optimize mob spawning
|
|
} else {
|
|
filteredSpawningCategories = List.of();
|
|
}
|
|
@@ -567,7 +616,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 - Pufferfish: Optimize mob spawning
|
|
}
|
|
} finally {
|
|
list.clear();
|
|
@@ -586,11 +635,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 - Pufferfish: Optimize 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 - Pufferfish: Optimize mob spawning
|
|
}
|
|
|
|
private void getFullChunk(long chunkPos, Consumer<LevelChunk> fullChunkGetter) {
|