Skip to content

Commit

Permalink
Async mob spawning (#88)
Browse files Browse the repository at this point in the history
  • Loading branch information
s-yh-china committed Aug 2, 2023
1 parent e651f8c commit 63548e5
Show file tree
Hide file tree
Showing 17 changed files with 208 additions and 79 deletions.
9 changes: 2 additions & 7 deletions patches/server/0004-Leaves-Server-Config-And-Command.patch
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,10 @@ index c9263cf970b82a2ee24d10202c21ac30bfd925dc..c20debb13d8496ad7c0ef1eaf5eae1c4
.withRequiredArg()
diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
new file mode 100644
index 0000000000000000000000000000000000000000..6373811568735b38d8812b29112b91c57f4d53ea
index 0000000000000000000000000000000000000000..ba0daabf8104b2a16169b65544eeeb948f04233f
--- /dev/null
+++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
@@ -0,0 +1,963 @@
@@ -0,0 +1,958 @@
+package top.leavesmc.leaves;
+
+import com.destroystokyo.paper.util.SneakyThrow;
Expand Down Expand Up @@ -369,11 +369,6 @@ index 0000000000000000000000000000000000000000..6373811568735b38d8812b29112b91c5
+ asyncMobSpawning = getBoolean("settings.performance.async-mob-spawning", asyncMobSpawning);
+ asyncMobSpawningLock = true;
+ }
+
+ if (asyncMobSpawning) {
+ asyncMobSpawning = false;
+ LeavesLogger.LOGGER.severe("Async MobSpawning is updating, it can't work");
+ }
+ }
+
+ public static boolean dontSendUselessEntityPackets = true;
Expand Down
159 changes: 148 additions & 11 deletions patches/server/0017-Optimize-mob-spawning.patch
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,153 @@ Subject: [PATCH] Optimize mob spawning

This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish)

diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
index 5922446ebbe64d1b001c505d6c5267417e0e7083..7a3086850da4894002a22d80d7f7cb9a1534cd6b 100644
--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java
+++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
@@ -238,7 +238,7 @@ public final class LeavesConfig {
noChatSign = getBoolean("settings.misc.no-chat-sign", noChatSign);
diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 307d4fd4b52aa654f859aab34126048b6a127dde..a1cf15fc45111508657efe3a4d7f48bfe27dcd9f 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -313,6 +313,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
public volatile boolean abnormalExit = false; // Paper
public boolean isIteratingOverLevels = false; // Paper

+ public top.leavesmc.leaves.util.AsyncExecutor mobSpawnExecutor = new top.leavesmc.leaves.util.AsyncExecutor("MobSpawning"); // Leaves - optimize mob spawning
+
public static <S extends MinecraftServer> S spin(Function<Thread, S> serverFactory) {
AtomicReference<S> atomicreference = new AtomicReference();
Thread thread = new io.papermc.paper.util.TickThread(() -> { // Paper - rewrite chunk system
diff --git a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
index 9abc92d8c98c1075ebc74e9dc4290b887913cc29..06cf3bbf50b941d3504de7198c5ca44ed5af2ff0 100644
--- a/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
+++ b/src/main/java/net/minecraft/server/dedicated/DedicatedServer.java
@@ -343,6 +343,11 @@ public class DedicatedServer extends MinecraftServer implements ServerInterface
DedicatedServer.LOGGER.info("JMX monitoring enabled");
}

+ // Leaves start - optimize mob spawning
+ if (top.leavesmc.leaves.LeavesConfig.asyncMobSpawning) {
+ mobSpawnExecutor.start();
+ }
+ // Leaves end - optimize mob spawning
return true;
}
}
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 469083208110d5735e1bbda7a15c55a032d0e8cc..cd063db781b461409ec3b3cfb499b43b8da07b54 100644
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
@@ -342,7 +342,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
this.dataRegionManager = new io.papermc.paper.chunk.SingleThreadChunkRegionManager(this.level, 2, (1.0 / 3.0), 1, 6, "Data", DataRegionData::new, DataRegionSectionData::new);
this.regionManagers.add(this.dataRegionManager);
// Paper end
- this.playerMobDistanceMap = this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper
+ this.playerMobDistanceMap = this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? top.leavesmc.leaves.LeavesConfig.asyncMobSpawning ? new top.leavesmc.leaves.util.AsyncPlayerAreaMap(this.pooledLinkedPlayerHashSets) : new com.destroystokyo.paper.util.misc.PlayerAreaMap(this.pooledLinkedPlayerHashSets) : null; // Paper // Leaves - optimize mob spawning
// Paper start - use distance map to optimise entity tracker
this.playerEntityTrackerTrackMaps = new com.destroystokyo.paper.util.misc.PlayerAreaMap[TRACKING_RANGE_TYPES.length];
this.entityTrackerTrackRanges = new int[TRACKING_RANGE_TYPES.length];
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 488a253e218409b5f0b4a872cee0928578fa7582..edafe1f60aab84b9eda5c4b7462552a3b23e19ff 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -77,6 +77,11 @@ public class ServerChunkCache extends ChunkSource {

private final LevelChunk[] lastLoadedChunks = new LevelChunk[4 * 4];

+ // Leaves start - optimize mob spawning
+ public boolean firstRunSpawnCounts = true;
+ public final java.util.concurrent.atomic.AtomicBoolean spawnCountsReady = new java.util.concurrent.atomic.AtomicBoolean(false);
+ // Leaves end - optimize mob spawning
+
private static int getChunkCacheKey(int x, int z) {
return x & 3 | ((z & 3) << 2);
}
@@ -562,18 +567,25 @@ public class ServerChunkCache extends ChunkSource {
// Paper start - per player mob spawning
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
- // re-set mob counts
- for (ServerPlayer player : this.level.players) {
- Arrays.fill(player.mobCounts, 0);
+ // Leaves start - optimize mob spawning
+ if (!top.leavesmc.leaves.LeavesConfig.asyncMobSpawning) {
+ // re-set mob counts
+ for (ServerPlayer player : this.level.players) {
+ Arrays.fill(player.mobCounts, 0);
+ }
+ 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
}
- spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, null, true);
- } else {
- spawnercreature_d = NaturalSpawner.createState(l, this.level.getAllEntities(), this::getFullChunk, this.chunkMap.playerMobDistanceMap == null ? new LocalMobCapCalculator(this.chunkMap) : null, false);
- }
// Paper end
this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings

- this.lastSpawnState = spawnercreature_d;
+ // this.lastSpawnState = spawnercreature_d; // Leaves - optimize mob spawning
gameprofilerfiller.popPush("filteringLoadedChunks");
// Paper - moved down
this.level.timings.chunkTicks.startTiming(); // Paper
@@ -612,9 +624,11 @@ 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);
- if (flag2 && (this.spawnEnemies || this.spawnFriendlies) && this.level.getWorldBorder().isWithinBounds(chunkcoordintpair) && this.chunkMap.anyPlayerCloseEnoughForSpawning(holder, chunkcoordintpair, true)) { // Spigot // Paper - optimise anyPlayerCloseEnoughForSpawning & optimise chunk tick iteration
- NaturalSpawner.spawnForChunk(this.level, chunk1, spawnercreature_d, this.spawnFriendlies, this.spawnEnemies, flag1);
+ // 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
+ NaturalSpawner.spawnForChunk(this.level, chunk1, lastSpawnState, this.spawnFriendlies, this.spawnEnemies, flag1);
}
+ // Leaves end - optimize mob spawning

if (true || this.level.shouldTickBlocksAt(chunkcoordintpair.toLong())) { // Paper - the chunk is known ticking
this.level.tickChunk(chunk1, k);
@@ -674,6 +688,30 @@ public class ServerChunkCache extends ChunkSource {
}
}
// Paper end - controlled flush for entity tracker packets
+
+ // Leaves start - optimize mob spawning
+ if (top.leavesmc.leaves.LeavesConfig.asyncMobSpawning) {
+ for (ServerPlayer player : this.level.players) {
+ Arrays.fill(player.mobCounts, 0);
+ }
+ if (firstRunSpawnCounts) {
+ firstRunSpawnCounts = false;
+ spawnCountsReady.set(true);
+ }
+ if (chunkMap.playerMobDistanceMap != null && spawnCountsReady.getAndSet(false)) {
+ net.minecraft.server.MinecraftServer.getServer().mobSpawnExecutor.submit(() -> {
+ int mapped = distanceManager.getNaturalSpawnChunkCount();
+ io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.Iterator<Entity> objectiterator =
+ level.entityTickList.entities.iterator(io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet.ITERATOR_FLAG_SEE_ADDITIONS);
+ top.leavesmc.leaves.util.IterableWrapper<Entity> wrappedIterator =
+ new top.leavesmc.leaves.util.IterableWrapper<Entity>(objectiterator);
+ lastSpawnState = NaturalSpawner.createState(mapped, wrappedIterator, this::getFullChunk, null, true);
+ objectiterator.finishedIterating();
+ spawnCountsReady.set(true);
+ });
+ }
+ }
+ // Leaves end - optimize mob spawning
}
}

diff --git a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
index 4cdfc433df67afcd455422e9baf56f167dd712ae..a6e0f5dab21d806e0c7744b2a337cded2739d870 100644
--- a/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
+++ b/src/main/java/net/minecraft/world/level/entity/EntityTickList.java
@@ -8,7 +8,7 @@ import javax.annotation.Nullable;
import net.minecraft.world.entity.Entity;

public class EntityTickList {
- private final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Entity> entities = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(true); // Paper - rewrite this, always keep this updated - why would we EVER tick an entity that's not ticking?
+ public final io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<Entity> entities = new io.papermc.paper.util.maplist.IteratorSafeOrderedReferenceSet<>(true); // Paper - rewrite this, always keep this updated - why would we EVER tick an entity that's not ticking? // Leaves - private -> public

- public static boolean asyncMobSpawning = false;
+ public static boolean asyncMobSpawning = false; // void
private static boolean asyncMobSpawningLock = false;
private static void asyncMobSpawning() {
if (!asyncMobSpawningLock) {
private void ensureActiveIsNotIterated() {
// Paper - replace with better logic, do not delay removals
4 changes: 2 additions & 2 deletions patches/server/0019-Multithreaded-Tracker.patch
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ Subject: [PATCH] Multithreaded Tracker
This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish)

diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
index 7a3086850da4894002a22d80d7f7cb9a1534cd6b..65ba44b49ecc31b4c54092e8eaf8c6c2a94e93f7 100644
index dd1c1c7abc5eb5ed9f32b321e4b971c730c8c556..615f45ab7521c821800b154464dac122e3f26ca4 100644
--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java
+++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
@@ -257,7 +257,7 @@ public final class LeavesConfig {
@@ -252,7 +252,7 @@ public final class LeavesConfig {
dontSendUselessEntityPackets = getBoolean("settings.performance.dont-send-useless-entity-packets", dontSendUselessEntityPackets);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ Subject: [PATCH] Optimize random calls in chunk ticking
This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish)

diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
index 488a253e218409b5f0b4a872cee0928578fa7582..a55ed382125310dfdfaeb7e80de2634a8d67f929 100644
index edafe1f60aab84b9eda5c4b7462552a3b23e19ff..b3d60819cee789c4cb3f7dcd2a8ea4aeb0b50f27 100644
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
@@ -553,6 +553,11 @@ public class ServerChunkCache extends ChunkSource {
@@ -558,6 +558,11 @@ public class ServerChunkCache extends ChunkSource {
ProfilerFiller gameprofilerfiller = this.level.getProfiler();

gameprofilerfiller.push("pollingChunks");
Expand Down
4 changes: 2 additions & 2 deletions patches/server/0030-Config-to-disable-method-profiler.patch
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ Subject: [PATCH] Config to disable method profiler
This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish)

diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 307d4fd4b52aa654f859aab34126048b6a127dde..755f0d3631b733799d2cb07a22b0bed8a7ab9e9d 100644
index a1cf15fc45111508657efe3a4d7f48bfe27dcd9f..a93018a2797bc1a1c134f810eaa067d0a0b4bb8a 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -2277,6 +2277,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -2279,6 +2279,11 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
}

public ProfilerFiller getProfiler() {
Expand Down
4 changes: 2 additions & 2 deletions patches/server/0037-Async-Pathfinding.patch
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ This patch is Powered by Pufferfish(https://github.com/pufferfish-gg/Pufferfish)
But Pufferfish patch was ported downstream from the Petal fork

diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
index 65ba44b49ecc31b4c54092e8eaf8c6c2a94e93f7..abfda50759834375ef810ecf5b4124510e9bb197 100644
index 615f45ab7521c821800b154464dac122e3f26ca4..c9ec0505c584d6e0a7ccd2b7286980b4fa157e2c 100644
--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java
+++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
@@ -358,7 +358,7 @@ public final class LeavesConfig {
@@ -353,7 +353,7 @@ public final class LeavesConfig {
// only config now
public static boolean asyncPathfinding = false;
private static boolean asyncPathfindingLock = false;
Expand Down
4 changes: 2 additions & 2 deletions patches/server/0044-BBOR-Protocol.patch
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ Subject: [PATCH] BBOR Protocol


diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java
index 755f0d3631b733799d2cb07a22b0bed8a7ab9e9d..e7f1e2440c067ebf8c1c2d175d413de6d27f5ff7 100644
index a93018a2797bc1a1c134f810eaa067d0a0b4bb8a..41fcf8abe96be28cdc79eba6eebe753deb38de2f 100644
--- a/src/main/java/net/minecraft/server/MinecraftServer.java
+++ b/src/main/java/net/minecraft/server/MinecraftServer.java
@@ -1601,6 +1601,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa
@@ -1603,6 +1603,8 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop<TickTa

this.profiler.popPush("server gui refresh");

Expand Down
6 changes: 3 additions & 3 deletions patches/server/0053-MC-Technical-Survival-Mode.patch
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ index e30d5ae3e2900f43d7cafde71b8196f26e872841..79bfd7b5da13197c2d3f7dbf9c3154dd
if (playerReputation != null) {
playerReputation.remove(GossipType.MAJOR_POSITIVE);
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
index c767257b56acbe2cde391f405c010f5b2f62a17c..4327ec0948fb82939272f2dc1bbde8b1e090c5b7 100644
index b0f23ebceb2f492b21eb95ee9496621f46c975c7..79f8e34032cde65a7d2a1f21bc32e0c22aff8efc 100644
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
@@ -95,7 +95,7 @@ public final class NaturalSpawner {
Expand All @@ -83,7 +83,7 @@ index c767257b56acbe2cde391f405c010f5b2f62a17c..4327ec0948fb82939272f2dc1bbde8b1
entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
continue;
diff --git a/src/main/java/top/leavesmc/leaves/LeavesConfig.java b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
index abfda50759834375ef810ecf5b4124510e9bb197..92bcaef8959a1adc5eb6cff1fb4ff2ddefdc7105 100644
index c9ec0505c584d6e0a7ccd2b7286980b4fa157e2c..eb6ad5d455d9038af539be2cd785e3fa274fc786 100644
--- a/src/main/java/top/leavesmc/leaves/LeavesConfig.java
+++ b/src/main/java/top/leavesmc/leaves/LeavesConfig.java
@@ -2,6 +2,7 @@ package top.leavesmc.leaves;
Expand All @@ -94,7 +94,7 @@ index abfda50759834375ef810ecf5b4124510e9bb197..92bcaef8959a1adc5eb6cff1fb4ff2dd
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.level.block.Blocks;
import net.minecraft.world.level.material.PushReaction;
@@ -478,6 +479,13 @@ public final class LeavesConfig {
@@ -473,6 +474,13 @@ public final class LeavesConfig {

public static void doMcTechnicalMode() {
if (mcTechnicalMode) {
Expand Down
Loading

0 comments on commit 63548e5

Please sign in to comment.