mirror of
https://github.com/Winds-Studio/Leaf.git
synced 2025-12-19 15:09:25 +00:00
backport 1.21.8 async mob spawn (#479)
* backport: 1.21.8 async mob spawn * Move into patch * fix * fix build --------- Co-authored-by: Dreeam <61569423+Dreeam-qwq@users.noreply.github.com> Co-authored-by: hayanesuru <hayanesuru@outlook.jp>
This commit is contained in:
@@ -4,8 +4,20 @@ Date: Tue, 3 Jun 2025 15:20:59 +0900
|
|||||||
Subject: [PATCH] optimize mob spawning
|
Subject: [PATCH] optimize mob spawning
|
||||||
|
|
||||||
|
|
||||||
|
diff --git a/net/minecraft/server/level/ChunkMap.java b/net/minecraft/server/level/ChunkMap.java
|
||||||
|
index f3be481a92b4f5403809c38d3b3431f4096d7a2e..2a5a2b6c28c61fe5cc3c89676472b9695fd3f188 100644
|
||||||
|
--- a/net/minecraft/server/level/ChunkMap.java
|
||||||
|
+++ b/net/minecraft/server/level/ChunkMap.java
|
||||||
|
@@ -280,6 +280,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
|
||||||
|
}
|
||||||
|
// Paper end - per player mob count backoff
|
||||||
|
public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
|
||||||
|
+ // Leaf - diff - async mob spawning - optimize mob spawning
|
||||||
|
return player.mobCounts[mobCategory.ordinal()] + player.mobBackoffCounts[mobCategory.ordinal()]; // Paper - per player mob count backoff
|
||||||
|
}
|
||||||
|
// Paper end - Optional per player mob spawns
|
||||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||||
index 52a2b993bbd1ad4851b3273af6ecbc069beb5b84..05df09d5f586c90f3169ddf1fa73a1d3fd734b73 100644
|
index 52a2b993bbd1ad4851b3273af6ecbc069beb5b84..f66f16332bd1af89a44b71bc015d52a2aeda09de 100644
|
||||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||||
+++ b/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
|
@@ -70,7 +70,9 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||||
@@ -19,7 +31,86 @@ index 52a2b993bbd1ad4851b3273af6ecbc069beb5b84..05df09d5f586c90f3169ddf1fa73a1d3
|
|||||||
// Paper start
|
// Paper start
|
||||||
public final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<net.minecraft.world.level.chunk.LevelChunk> fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>();
|
public final ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<net.minecraft.world.level.chunk.LevelChunk> fullChunks = new ca.spottedleaf.concurrentutil.map.ConcurrentLong2ReferenceChainedHashTable<>();
|
||||||
public int getFullChunksCount() {
|
public int getFullChunksCount() {
|
||||||
@@ -658,13 +660,37 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
@@ -496,6 +498,23 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||||
|
long gameTime = this.level.getGameTime();
|
||||||
|
long l = gameTime - this.lastInhabitedUpdate;
|
||||||
|
this.lastInhabitedUpdate = gameTime;
|
||||||
|
+ // Leaf start - optimize mob spawning
|
||||||
|
+ if (org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled && level.paperConfig().entities.spawning.perPlayerMobSpawns) {
|
||||||
|
+ 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;
|
||||||
|
+ }
|
||||||
|
+ // Paper end - per player mob spawning backoff
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Leaf end - optimize mob spawning
|
||||||
|
if (!this.level.isDebug()) {
|
||||||
|
this.level.resetIceAndSnowTick(); // Gale - Airplane - optimize random calls in chunk ticking - reset ice & snow tick random
|
||||||
|
if (this.level.tickRateManager().runsNormally()) {
|
||||||
|
@@ -518,8 +537,8 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pufferfish start - optimize mob spawning
|
||||||
|
- if (org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled) {
|
||||||
|
- for (ServerPlayer player : this.level.players) {
|
||||||
|
+ if (org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled && level.paperConfig().entities.spawning.perPlayerMobSpawns) {
|
||||||
|
+ /*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;
|
||||||
|
@@ -531,34 +550,21 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||||
|
player.mobBackoffCounts[ii] = newBackoff;
|
||||||
|
}
|
||||||
|
// Paper end - per player mob spawning backoff
|
||||||
|
- }
|
||||||
|
+ }*/
|
||||||
|
if (firstRunSpawnCounts) {
|
||||||
|
firstRunSpawnCounts = false;
|
||||||
|
_pufferfish_spawnCountsReady.set(true);
|
||||||
|
}
|
||||||
|
if (_pufferfish_spawnCountsReady.getAndSet(false)) {
|
||||||
|
+ final int mapped = distanceManager.getNaturalSpawnChunkCount();
|
||||||
|
+ final Iterable<Entity> entities = this.level.getAllEntities();
|
||||||
|
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);
|
||||||
|
- // Fix: Use proper mob cap calculator based on configuration
|
||||||
|
- LocalMobCapCalculator mobCapCalculator = !level.paperConfig().entities.spawning.perPlayerMobSpawns ?
|
||||||
|
- new LocalMobCapCalculator(chunkMap) : null;
|
||||||
|
-
|
||||||
|
- // This ensures the caps are properly enforced by using the correct calculator
|
||||||
|
- lastSpawnState = NaturalSpawner.createState(
|
||||||
|
- mapped,
|
||||||
|
- wrappedIterator,
|
||||||
|
- ServerChunkCache.this::getFullChunk,
|
||||||
|
- mobCapCalculator, // This is the key fix - was previously null
|
||||||
|
- level.paperConfig().entities.spawning.perPlayerMobSpawns
|
||||||
|
- );
|
||||||
|
- } finally {
|
||||||
|
- objectiterator.finishedIterating();
|
||||||
|
- }
|
||||||
|
+ lastSpawnState = NaturalSpawner.createState1(
|
||||||
|
+ mapped,
|
||||||
|
+ entities,
|
||||||
|
+ this.level
|
||||||
|
+ );
|
||||||
|
+ // Leaf end - optimize mob spawning
|
||||||
|
_pufferfish_spawnCountsReady.set(true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@@ -658,13 +664,38 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||||
filteredSpawningCategories = List.of();
|
filteredSpawningCategories = List.of();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -30,7 +121,8 @@ index 52a2b993bbd1ad4851b3273af6ecbc069beb5b84..05df09d5f586c90f3169ddf1fa73a1d3
|
|||||||
- NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState, filteredSpawningCategories); // Pufferfish
|
- NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState, filteredSpawningCategories); // Pufferfish
|
||||||
+ // Leaf start - optimize mob spawning
|
+ // Leaf start - optimize mob spawning
|
||||||
+ var lastSpawnState1 = this.lastSpawnState;
|
+ var lastSpawnState1 = this.lastSpawnState;
|
||||||
+ if (lastSpawnState1 != null && (!org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled || _pufferfish_spawnCountsReady.get())) {
|
+ if (lastSpawnState1 != null && (!org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled || !level.paperConfig().entities.spawning.perPlayerMobSpawns || _pufferfish_spawnCountsReady.get())) {
|
||||||
|
+ lastSpawnState1.applyPerPlayerMobCount(level); // Leaf - optimize mob spawning
|
||||||
+ long sumTimeInhabited = timeInhabited + delayTimeInhabited;
|
+ long sumTimeInhabited = timeInhabited + delayTimeInhabited;
|
||||||
+ long time = level.getGameTime();
|
+ long time = level.getGameTime();
|
||||||
+ for (LevelChunk levelChunk : chunks) {
|
+ for (LevelChunk levelChunk : chunks) {
|
||||||
@@ -39,7 +131,7 @@ index 52a2b993bbd1ad4851b3273af6ecbc069beb5b84..05df09d5f586c90f3169ddf1fa73a1d3
|
|||||||
+ if (!filteredSpawningCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && this.chunkMap.anyPlayerCloseEnoughForSpawning(pos, true)) { // Spigot
|
+ if (!filteredSpawningCategories.isEmpty() && this.level.getWorldBorder().isWithinBounds(pos) && this.chunkMap.anyPlayerCloseEnoughForSpawning(pos, true)) { // Spigot
|
||||||
+ NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState1, filteredSpawningCategories, time); // Pufferfish
|
+ NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState1, filteredSpawningCategories, time); // Pufferfish
|
||||||
+ }
|
+ }
|
||||||
+ }
|
}
|
||||||
+ if (delaySpawn != -1L) {
|
+ if (delaySpawn != -1L) {
|
||||||
+ time = delaySpawn;
|
+ time = delaySpawn;
|
||||||
+ for (LevelChunk levelChunk : chunks) {
|
+ for (LevelChunk levelChunk : chunks) {
|
||||||
@@ -48,7 +140,7 @@ index 52a2b993bbd1ad4851b3273af6ecbc069beb5b84..05df09d5f586c90f3169ddf1fa73a1d3
|
|||||||
+ NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState1, filteredSpawningCategories, time); // Pufferfish
|
+ NaturalSpawner.spawnForChunk(this.level, levelChunk, lastSpawnState1, filteredSpawningCategories, time); // Pufferfish
|
||||||
+ }
|
+ }
|
||||||
+ }
|
+ }
|
||||||
}
|
+ }
|
||||||
+ delaySpawn = -1L;
|
+ delaySpawn = -1L;
|
||||||
+ delayTimeInhabited = 0L;
|
+ delayTimeInhabited = 0L;
|
||||||
+ } else {
|
+ } else {
|
||||||
@@ -63,10 +155,85 @@ index 52a2b993bbd1ad4851b3273af6ecbc069beb5b84..05df09d5f586c90f3169ddf1fa73a1d3
|
|||||||
this.level.tickChunk(levelChunk, _int);
|
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 9b37b763c6555705f3e256010f508b5a0c2cdb66..8f999b425bce52352a04ee3ca11b6854194dd665 100644
|
index 9b37b763c6555705f3e256010f508b5a0c2cdb66..418fd9db5a06af5369da597762c0757453929f83 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
|
||||||
@@ -155,7 +155,13 @@ public final class NaturalSpawner {
|
@@ -74,6 +74,7 @@ public final class NaturalSpawner {
|
||||||
|
return createState(spawnableChunkCount, entities, chunkGetter, calculator, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
+ @Deprecated // Leaf - optimize mob spawning
|
||||||
|
public static NaturalSpawner.SpawnState createState(
|
||||||
|
int spawnableChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkGetter, LocalMobCapCalculator calculator, final boolean countMobs
|
||||||
|
) {
|
||||||
|
@@ -114,9 +115,65 @@ public final class NaturalSpawner {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- return new NaturalSpawner.SpawnState(spawnableChunkCount, map, potentialCalculator, calculator);
|
||||||
|
+ return new NaturalSpawner.SpawnState(spawnableChunkCount, map, potentialCalculator, calculator, new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>()); // Leaf - optimize mob spawning
|
||||||
|
}
|
||||||
|
|
||||||
|
+ // Leaf start - optimize mob spawning
|
||||||
|
+ public static NaturalSpawner.SpawnState createState1(
|
||||||
|
+ int spawnableChunkCount, Iterable<Entity> entities, ServerLevel level
|
||||||
|
+ ) {
|
||||||
|
+ // Paper end - Optional per player mob spawns
|
||||||
|
+ PotentialCalculator potentialCalculator = new PotentialCalculator();
|
||||||
|
+ Object2IntOpenHashMap<MobCategory> map = new Object2IntOpenHashMap<>();
|
||||||
|
+ it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<int[]> chunkCap = new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>();
|
||||||
|
+ boolean countAllMobsForSpawning = level.paperConfig().entities.spawning.countAllMobsForSpawning;
|
||||||
|
+ for (Entity entity : entities) {
|
||||||
|
+ if (!(entity instanceof Mob mob && (mob.isPersistenceRequired() || mob.requiresCustomPersistence()))) {
|
||||||
|
+ MobCategory category = entity.getType().getCategory();
|
||||||
|
+ if (category != MobCategory.MISC) {
|
||||||
|
+ // Paper start - Only count natural spawns
|
||||||
|
+ if (!countAllMobsForSpawning &&
|
||||||
|
+ !(entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.NATURAL ||
|
||||||
|
+ entity.spawnReason == org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CHUNK_GEN)) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ // Paper end - Only count natural spawns
|
||||||
|
+ BlockPos blockPos = entity.blockPosition();
|
||||||
|
+ LevelChunk chunk = level.getChunkSource().getChunkNow(blockPos.getX() >> 4, blockPos.getZ() >> 4);
|
||||||
|
+ if (chunk != null) {
|
||||||
|
+ MobSpawnSettings.MobSpawnCost mobSpawnCost = getRoughBiome(blockPos, chunk).getMobSettings().getMobSpawnCost(entity.getType());
|
||||||
|
+ if (mobSpawnCost != null) {
|
||||||
|
+ potentialCalculator.addCharge(entity.blockPosition(), mobSpawnCost.charge());
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ map.addTo(category, 1);
|
||||||
|
+ // Paper start - Optional per player mob spawns
|
||||||
|
+ final int index = entity.getType().getCategory().ordinal();
|
||||||
|
+ ++chunkCap.computeIfAbsent(chunk.getPos().toLong(), k -> new int[net.minecraft.server.level.ServerPlayer.MOBCATEGORY_TOTAL_ENUMS])[index];
|
||||||
|
+ /*
|
||||||
|
+ final int index = entity.getType().getCategory().ordinal();
|
||||||
|
+ final var inRange = level.moonrise$getNearbyPlayers().getPlayers(entity.chunkPosition(), NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
|
||||||
|
+ if (inRange == null) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ final net.minecraft.server.level.ServerPlayer[] backingSet = inRange.getRawDataUnchecked();
|
||||||
|
+ for (int i = 0, len = inRange.size(); i < len; i++) {
|
||||||
|
+ final net.minecraft.server.level.ServerPlayer player = backingSet[i];
|
||||||
|
+ if (player == null) continue;
|
||||||
|
+ ++playerCap.computeIfAbsent(player, k -> new int[net.minecraft.server.level.ServerPlayer.MOBCATEGORY_TOTAL_ENUMS])[index];
|
||||||
|
+ }
|
||||||
|
+ */
|
||||||
|
+ // Paper end - Optional per player mob spawns
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ return new NaturalSpawner.SpawnState(spawnableChunkCount, map, potentialCalculator, null, chunkCap);
|
||||||
|
+ }
|
||||||
|
+ // Leaf end - optimize mob spawning
|
||||||
|
+
|
||||||
|
static Biome getRoughBiome(BlockPos pos, ChunkAccess chunk) {
|
||||||
|
return chunk.getNoiseBiome(QuartPos.fromBlock(pos.getX()), QuartPos.fromBlock(pos.getY()), QuartPos.fromBlock(pos.getZ())).value();
|
||||||
|
}
|
||||||
|
@@ -155,7 +212,13 @@ public final class NaturalSpawner {
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,7 +247,7 @@ index 9b37b763c6555705f3e256010f508b5a0c2cdb66..8f999b425bce52352a04ee3ca11b6854
|
|||||||
for (MobCategory mobCategory : categories) {
|
for (MobCategory mobCategory : categories) {
|
||||||
// Paper start - Optional per player mob spawns
|
// Paper start - Optional per player mob spawns
|
||||||
final boolean canSpawn;
|
final boolean canSpawn;
|
||||||
@@ -174,7 +180,7 @@ public final class NaturalSpawner {
|
@@ -174,7 +237,7 @@ public final class NaturalSpawner {
|
||||||
}
|
}
|
||||||
// Paper end - throttle failed spawn attempts
|
// Paper end - throttle failed spawn attempts
|
||||||
if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
|
if (CraftSpawnCategory.isValidForLimits(spawnCategory)) {
|
||||||
@@ -89,7 +256,7 @@ index 9b37b763c6555705f3e256010f508b5a0c2cdb66..8f999b425bce52352a04ee3ca11b6854
|
|||||||
limit = level.getWorld().getSpawnLimit(spawnCategory);
|
limit = level.getWorld().getSpawnLimit(spawnCategory);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -238,12 +244,14 @@ public final class NaturalSpawner {
|
@@ -238,12 +301,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
|
||||||
@@ -109,7 +276,7 @@ index 9b37b763c6555705f3e256010f508b5a0c2cdb66..8f999b425bce52352a04ee3ca11b6854
|
|||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForDebug
|
@VisibleForDebug
|
||||||
@@ -275,31 +283,59 @@ public final class NaturalSpawner {
|
@@ -275,31 +340,59 @@ 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();
|
||||||
@@ -177,7 +344,7 @@ index 9b37b763c6555705f3e256010f508b5a0c2cdb66..8f999b425bce52352a04ee3ca11b6854
|
|||||||
if (spawnerData == null) {
|
if (spawnerData == null) {
|
||||||
Optional<MobSpawnSettings.SpawnerData> randomSpawnMobAt = getRandomSpawnMobAt(
|
Optional<MobSpawnSettings.SpawnerData> randomSpawnMobAt = getRandomSpawnMobAt(
|
||||||
level, structureManager, generator, category, level.random, mutableBlockPos
|
level, structureManager, generator, category, level.random, mutableBlockPos
|
||||||
@@ -368,8 +404,8 @@ public final class NaturalSpawner {
|
@@ -368,8 +461,8 @@ public final class NaturalSpawner {
|
||||||
|
|
||||||
private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel level, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double distance) {
|
private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel level, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double distance) {
|
||||||
return !(distance <= 576.0)
|
return !(distance <= 576.0)
|
||||||
@@ -188,7 +355,7 @@ index 9b37b763c6555705f3e256010f508b5a0c2cdb66..8f999b425bce52352a04ee3ca11b6854
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Paper start - PreCreatureSpawnEvent
|
// Paper start - PreCreatureSpawnEvent
|
||||||
@@ -474,6 +510,17 @@ public final class NaturalSpawner {
|
@@ -474,6 +567,17 @@ public final class NaturalSpawner {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,3 +373,72 @@ index 9b37b763c6555705f3e256010f508b5a0c2cdb66..8f999b425bce52352a04ee3ca11b6854
|
|||||||
private static BlockPos getRandomPosWithin(Level level, LevelChunk chunk) {
|
private static BlockPos getRandomPosWithin(Level level, LevelChunk chunk) {
|
||||||
ChunkPos pos = chunk.getPos();
|
ChunkPos pos = chunk.getPos();
|
||||||
int i = pos.getMinBlockX() + level.random.nextInt(16);
|
int i = pos.getMinBlockX() + level.random.nextInt(16);
|
||||||
|
@@ -614,18 +718,21 @@ public final class NaturalSpawner {
|
||||||
|
@Nullable
|
||||||
|
private EntityType<?> lastCheckedType;
|
||||||
|
private double lastCharge;
|
||||||
|
+ public final it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<int[]> chunkCap; // Leaf - optimize mob spawning
|
||||||
|
|
||||||
|
SpawnState(
|
||||||
|
int spawnableChunkCount,
|
||||||
|
Object2IntOpenHashMap<MobCategory> mobCategoryCounts,
|
||||||
|
PotentialCalculator spawnPotential,
|
||||||
|
- LocalMobCapCalculator localMobCapCalculator
|
||||||
|
+ LocalMobCapCalculator localMobCapCalculator,
|
||||||
|
+ it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<int[]> playerCap // Leaf - optimize mob spawning
|
||||||
|
) {
|
||||||
|
this.spawnableChunkCount = spawnableChunkCount;
|
||||||
|
this.mobCategoryCounts = mobCategoryCounts;
|
||||||
|
this.spawnPotential = spawnPotential;
|
||||||
|
this.localMobCapCalculator = localMobCapCalculator;
|
||||||
|
this.unmodifiableMobCategoryCounts = Object2IntMaps.unmodifiable(mobCategoryCounts);
|
||||||
|
+ this.chunkCap = playerCap; // Leaf - optimize mob spawning
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean canSpawn(EntityType<?> entityType, BlockPos pos, ChunkAccess chunk) {
|
||||||
|
@@ -682,5 +789,32 @@ public final class NaturalSpawner {
|
||||||
|
boolean canSpawnForCategoryLocal(MobCategory category, ChunkPos chunkPos) {
|
||||||
|
return this.localMobCapCalculator.canSpawn(category, chunkPos);
|
||||||
|
}
|
||||||
|
+
|
||||||
|
+ // Leaf start - optimize mob spawning
|
||||||
|
+ public void applyPerPlayerMobCount(ServerLevel level) {
|
||||||
|
+ if (chunkCap.isEmpty()) {
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ final var iterator = chunkCap.long2ObjectEntrySet().fastIterator();
|
||||||
|
+ final ca.spottedleaf.moonrise.common.misc.NearbyPlayers nearbyPlayers = level.moonrise$getNearbyPlayers();
|
||||||
|
+ while (iterator.hasNext()) {
|
||||||
|
+ var entry = iterator.next();
|
||||||
|
+ long chunk = entry.getLongKey();
|
||||||
|
+ int[] cap = entry.getValue();
|
||||||
|
+ ca.spottedleaf.moonrise.common.list.ReferenceList<net.minecraft.server.level.ServerPlayer> players = nearbyPlayers.getPlayersByChunk(net.minecraft.world.level.ChunkPos.getX(chunk), net.minecraft.world.level.ChunkPos.getZ(chunk), ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
|
||||||
|
+ if (players == null) {
|
||||||
|
+ continue;
|
||||||
|
+ }
|
||||||
|
+ int playersSize = players.size();
|
||||||
|
+ net.minecraft.server.level.ServerPlayer[] playersRawDataUnchecked = players.getRawDataUnchecked();
|
||||||
|
+ for (int i = 0; i < playersSize; i++) {
|
||||||
|
+ int[] p = playersRawDataUnchecked[i].mobCounts;
|
||||||
|
+ for (int j = 0; j < net.minecraft.server.level.ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; j++) {
|
||||||
|
+ p[j] += cap[j];
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ // Leaf end - optimize mob spawning
|
||||||
|
}
|
||||||
|
}
|
||||||
|
diff --git a/net/minecraft/world/level/entity/EntityTickList.java b/net/minecraft/world/level/entity/EntityTickList.java
|
||||||
|
index 5a90b3bffeeb08a168b370e49d18c5f8b257a980..ba173bc1751c495e6fa497566b5ed3c7a9547364 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<net.minecraft.world.entity.Entity> entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled); // Paper - rewrite chunk system // Pufferfish - private->public and do thread check
|
||||||
|
+ private final ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<net.minecraft.world.entity.Entity> entities = new ca.spottedleaf.moonrise.common.list.IteratorSafeOrderedReferenceSet<>(); // Paper - rewrite chunk system
|
||||||
|
|
||||||
|
// Leaf start - SparklyPaper - parallel world ticking mod
|
||||||
|
// preserve original constructor
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ 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 8f999b425bce52352a04ee3ca11b6854194dd665..48ab439560c6ba83d34163cc7402146e69e7c277 100644
|
index 6e911df433013480c2688c086a7ff1de321001bc..7764fcca95cef9f0aa46683f41d3a6805507f80a 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
|
||||||
@@ -166,6 +166,17 @@ public final class NaturalSpawner {
|
@@ -223,6 +223,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;
|
||||||
|
|||||||
@@ -100,10 +100,10 @@ index 4535858701b2bb232b9d2feb2af6551526232ddc..e65c62dbe4c1560ae153e4c4344e9194
|
|||||||
- // Paper end - detailed watchdog information
|
- // Paper end - detailed watchdog information
|
||||||
}
|
}
|
||||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||||
index 05df09d5f586c90f3169ddf1fa73a1d3fd734b73..fbcff9a0e4aa68375e7ebcc297ba4a7bf089c4f3 100644
|
index f66f16332bd1af89a44b71bc015d52a2aeda09de..bb200d3f482c7f623a827d255a9633bb278637e9 100644
|
||||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||||
@@ -506,9 +506,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
@@ -523,9 +523,10 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||||
try {
|
try {
|
||||||
this.collectTickingChunks(list);
|
this.collectTickingChunks(list);
|
||||||
// Paper start - chunk tick iteration optimisation
|
// Paper start - chunk tick iteration optimisation
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ Subject: [PATCH] optimize random tick
|
|||||||
|
|
||||||
|
|
||||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||||
index fbcff9a0e4aa68375e7ebcc297ba4a7bf089c4f3..e07fdd22e08cb4e30cf606c055e85b5946e8c046 100644
|
index bb200d3f482c7f623a827d255a9633bb278637e9..7531e684e16bc038811fbf133caced9c7f5efe07 100644
|
||||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||||
@@ -696,6 +696,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
@@ -701,6 +701,7 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||||
this.level.tickChunk(levelChunk, _int);
|
this.level.tickChunk(levelChunk, _int);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,10 +5,10 @@ Subject: [PATCH] count all chunks for ticking
|
|||||||
|
|
||||||
|
|
||||||
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java
|
||||||
index e07fdd22e08cb4e30cf606c055e85b5946e8c046..432c98b582ab40f893835a7a24ef9bbdacc49bd7 100644
|
index 7531e684e16bc038811fbf133caced9c7f5efe07..10fb9cc994ddc8820bed23d722b49b9f33e5fc09 100644
|
||||||
--- a/net/minecraft/server/level/ServerChunkCache.java
|
--- a/net/minecraft/server/level/ServerChunkCache.java
|
||||||
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
+++ b/net/minecraft/server/level/ServerChunkCache.java
|
||||||
@@ -589,6 +589,14 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
@@ -593,6 +593,14 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon
|
||||||
final int size = tickingChunks.size();
|
final int size = tickingChunks.size();
|
||||||
|
|
||||||
final ChunkMap chunkMap = this.chunkMap;
|
final ChunkMap chunkMap = this.chunkMap;
|
||||||
|
|||||||
@@ -1,190 +0,0 @@
|
|||||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
|
||||||
From: Kevin Raneri <kevin.raneri@gmail.com>
|
|
||||||
Date: Wed, 10 Nov 2021 00:37:03 -0500
|
|
||||||
Subject: [PATCH] Pufferfish: Optimize mob spawning
|
|
||||||
|
|
||||||
Original license: GPL v3
|
|
||||||
Original project: https://github.com/pufferfish-gg/Pufferfish
|
|
||||||
|
|
||||||
Co-authored-by: booky10 <boooky10@gmail.com>
|
|
||||||
Co-authored-by: HaHaWTH <102713261+HaHaWTH@users.noreply.github.com>
|
|
||||||
|
|
||||||
This patch aims to reduce the main-thread impact of mob spawning by
|
|
||||||
offloading as much work as possible to other threads. It is possible for
|
|
||||||
inconsistencies to come up, but when they happen they never interfere
|
|
||||||
with the server's operation (they don't produce errors), and side
|
|
||||||
effects are limited to more or less mobs being spawned in any particular
|
|
||||||
tick.
|
|
||||||
|
|
||||||
It is possible to disable this optimization if it is not required or if
|
|
||||||
it interferes with any plugins. On servers with thousands of entities,
|
|
||||||
this can result in performance gains of up to 15%, which is significant
|
|
||||||
and, in my opinion, worth the low risk of minor mob-spawning-related
|
|
||||||
inconsistencies.
|
|
||||||
|
|
||||||
diff --git a/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java b/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java
|
|
||||||
index c21e00812f1aaa1279834a0562d360d6b89e146c..bc06820e9e68e0ad2f8e4cb1a73d04aedf3f3e40 100644
|
|
||||||
--- a/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java
|
|
||||||
+++ b/src/main/java/ca/spottedleaf/moonrise/common/list/IteratorSafeOrderedReferenceSet.java
|
|
||||||
@@ -10,7 +10,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|
||||||
public static final int ITERATOR_FLAG_SEE_ADDITIONS = 1 << 0;
|
|
||||||
|
|
||||||
private final Reference2IntLinkedOpenHashMap<E> indexMap;
|
|
||||||
- private int firstInvalidIndex = -1;
|
|
||||||
+ private final java.util.concurrent.atomic.AtomicInteger firstInvalidIndex = new java.util.concurrent.atomic.AtomicInteger(-1); // Leaf - Pufferfish - Async mob spawning - atomic
|
|
||||||
|
|
||||||
/* list impl */
|
|
||||||
private E[] listElements;
|
|
||||||
@@ -18,18 +18,32 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|
||||||
|
|
||||||
private final double maxFragFactor;
|
|
||||||
|
|
||||||
- private int iteratorCount;
|
|
||||||
+ private int iteratorCount; // Pufferfish - async mob spawning
|
|
||||||
+
|
|
||||||
+ // Pufferfish start - async mob spawning
|
|
||||||
+ private final boolean threadRestricted;
|
|
||||||
|
|
||||||
public IteratorSafeOrderedReferenceSet() {
|
|
||||||
- this(16, 0.75f, 16, 0.2);
|
|
||||||
+ this(16, 0.75f, 16, 0.2, false);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ public IteratorSafeOrderedReferenceSet(final boolean threadRestricted) {
|
|
||||||
+ this(16, 0.75f, 16, 0.2, threadRestricted);
|
|
||||||
}
|
|
||||||
|
|
||||||
public IteratorSafeOrderedReferenceSet(final int setCapacity, final float setLoadFactor, final int arrayCapacity,
|
|
||||||
final double maxFragFactor) {
|
|
||||||
+ this(setCapacity, setLoadFactor, arrayCapacity, maxFragFactor, false);
|
|
||||||
+ }
|
|
||||||
+
|
|
||||||
+ public IteratorSafeOrderedReferenceSet(final int setCapacity, final float setLoadFactor, final int arrayCapacity,
|
|
||||||
+ final double maxFragFactor, final boolean threadRestricted) {
|
|
||||||
this.indexMap = new Reference2IntLinkedOpenHashMap<>(setCapacity, setLoadFactor);
|
|
||||||
this.indexMap.defaultReturnValue(-1);
|
|
||||||
this.maxFragFactor = maxFragFactor;
|
|
||||||
this.listElements = (E[])new Object[arrayCapacity];
|
|
||||||
+ this.threadRestricted = threadRestricted;
|
|
||||||
+ // Pufferfish end - async mob spawning
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
@@ -74,16 +88,24 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
+ // Pufferfish start - async mob spawning
|
|
||||||
+ // Bring back allowSafeIteration from Paper 1.20.4
|
|
||||||
+ // To defrag only on the main thread
|
|
||||||
+ private boolean allowSafeIteration() {
|
|
||||||
+ return !this.threadRestricted || ca.spottedleaf.moonrise.common.util.TickThread.isTickThread();
|
|
||||||
+ }
|
|
||||||
+ // Pufferfish end - async mob spawning
|
|
||||||
+
|
|
||||||
private double getFragFactor() {
|
|
||||||
return 1.0 - ((double)this.indexMap.size() / (double)this.listSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int createRawIterator() {
|
|
||||||
- ++this.iteratorCount;
|
|
||||||
+ if (this.allowSafeIteration()) this.iteratorCount++; // Pufferfish - async mob spawning
|
|
||||||
if (this.indexMap.isEmpty()) {
|
|
||||||
return -1;
|
|
||||||
} else {
|
|
||||||
- return this.firstInvalidIndex == 0 ? this.indexMap.getInt(this.indexMap.firstKey()) : 0;
|
|
||||||
+ return this.firstInvalidIndex.get() == 0 ? this.indexMap.getInt(this.indexMap.firstKey()) : 0; // Leaf - Pufferfish - Async mob spawning
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -100,7 +122,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|
||||||
}
|
|
||||||
|
|
||||||
public void finishRawIterator() {
|
|
||||||
- if (--this.iteratorCount == 0) {
|
|
||||||
+ if (--this.iteratorCount == 0) { // Pufferfish - async mob spawning
|
|
||||||
if (this.getFragFactor() >= this.maxFragFactor) {
|
|
||||||
this.defrag();
|
|
||||||
}
|
|
||||||
@@ -110,14 +132,17 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|
||||||
public boolean remove(final E element) {
|
|
||||||
final int index = this.indexMap.removeInt(element);
|
|
||||||
if (index >= 0) {
|
|
||||||
- if (this.firstInvalidIndex < 0 || index < this.firstInvalidIndex) {
|
|
||||||
- this.firstInvalidIndex = index;
|
|
||||||
+ // Leaf start - Pufferfish - Async mob spawning
|
|
||||||
+ int firstInvalidIndex = this.firstInvalidIndex.get();
|
|
||||||
+ if (firstInvalidIndex < 0 || index < firstInvalidIndex) {
|
|
||||||
+ this.firstInvalidIndex.set(index);
|
|
||||||
}
|
|
||||||
+ // Leaf end - Pufferfish - Async mob spawning
|
|
||||||
if (this.listElements[index] != element) {
|
|
||||||
throw new IllegalStateException();
|
|
||||||
}
|
|
||||||
this.listElements[index] = null;
|
|
||||||
- if (this.iteratorCount == 0 && this.getFragFactor() >= this.maxFragFactor) {
|
|
||||||
+ if (this.allowSafeIteration() && this.iteratorCount == 0 && this.getFragFactor() >= this.maxFragFactor) { // Pufferfish - async mob spawning
|
|
||||||
this.defrag();
|
|
||||||
}
|
|
||||||
//this.check();
|
|
||||||
@@ -149,14 +174,17 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|
||||||
}
|
|
||||||
|
|
||||||
private void defrag() {
|
|
||||||
- if (this.firstInvalidIndex < 0) {
|
|
||||||
+ // Leaf start - Pufferfish - Async mob spawning
|
|
||||||
+ int firstInvalidIndex = this.firstInvalidIndex.get();
|
|
||||||
+ if (firstInvalidIndex < 0) {
|
|
||||||
return; // nothing to do
|
|
||||||
}
|
|
||||||
+ // Leaf end - Pufferfish - Async mob spawning
|
|
||||||
|
|
||||||
if (this.indexMap.isEmpty()) {
|
|
||||||
Arrays.fill(this.listElements, 0, this.listSize, null);
|
|
||||||
this.listSize = 0;
|
|
||||||
- this.firstInvalidIndex = -1;
|
|
||||||
+ this.firstInvalidIndex.set(-1); // Leaf - Pufferfish - Async mob spawning
|
|
||||||
//this.check();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
@@ -166,11 +194,11 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|
||||||
int lastValidIndex;
|
|
||||||
java.util.Iterator<Reference2IntMap.Entry<E>> iterator;
|
|
||||||
|
|
||||||
- if (this.firstInvalidIndex == 0) {
|
|
||||||
+ if (firstInvalidIndex == 0) { // Leaf - Pufferfish - Async mob spawning
|
|
||||||
iterator = this.indexMap.reference2IntEntrySet().fastIterator();
|
|
||||||
lastValidIndex = 0;
|
|
||||||
} else {
|
|
||||||
- lastValidIndex = this.firstInvalidIndex;
|
|
||||||
+ lastValidIndex = firstInvalidIndex; // Leaf - Pufferfish - Async mob spawning
|
|
||||||
final E key = backingArray[lastValidIndex - 1];
|
|
||||||
iterator = this.indexMap.reference2IntEntrySet().fastIterator(new Reference2IntMap.Entry<E>() {
|
|
||||||
@Override
|
|
||||||
@@ -201,7 +229,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|
||||||
// cleanup end
|
|
||||||
Arrays.fill(backingArray, lastValidIndex, this.listSize, null);
|
|
||||||
this.listSize = lastValidIndex;
|
|
||||||
- this.firstInvalidIndex = -1;
|
|
||||||
+ this.firstInvalidIndex.set(-1); // Leaf - Pufferfish - Async mob spawning
|
|
||||||
//this.check();
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -219,7 +247,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|
||||||
}
|
|
||||||
|
|
||||||
public IteratorSafeOrderedReferenceSet.Iterator<E> iterator(final int flags) {
|
|
||||||
- ++this.iteratorCount;
|
|
||||||
+ if (this.allowSafeIteration()) ++this.iteratorCount; // Pufferfish - async mob spawning
|
|
||||||
return new BaseIterator<>(this, true, (flags & ITERATOR_FLAG_SEE_ADDITIONS) != 0 ? Integer.MAX_VALUE : this.listSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -306,7 +334,7 @@ public final class IteratorSafeOrderedReferenceSet<E> {
|
|
||||||
}
|
|
||||||
this.lastReturned = null;
|
|
||||||
this.finished = true;
|
|
||||||
- this.set.finishRawIterator();
|
|
||||||
+ if (this.set.allowSafeIteration()) this.set.finishRawIterator(); // Pufferfish - async mob spawning - diff on change
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user