diff --git a/leaf-server/minecraft-patches/features/0263-optimize-mob-spawning.patch b/leaf-server/minecraft-patches/features/0263-optimize-mob-spawning.patch index cac42df2..045df112 100644 --- a/leaf-server/minecraft-patches/features/0263-optimize-mob-spawning.patch +++ b/leaf-server/minecraft-patches/features/0263-optimize-mob-spawning.patch @@ -17,7 +17,7 @@ index 79674f4bd7a12c42dec19a4175012d7a2dc88b84..9f4ba5b7e054bbe70a820068f22fe8a6 } // Paper end - Optional per player mob spawns diff --git a/net/minecraft/server/level/ServerChunkCache.java b/net/minecraft/server/level/ServerChunkCache.java -index 46e171ca454253c32e22c0c18587e9a7ba19f331..fd7f38558a598192703a8d79fc4d3818abb2551c 100644 +index 46e171ca454253c32e22c0c18587e9a7ba19f331..51b4a043c09eef84bf926ea02bf588e9ce900788 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java @@ -70,11 +70,11 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon @@ -47,7 +47,7 @@ index 46e171ca454253c32e22c0c18587e9a7ba19f331..fd7f38558a598192703a8d79fc4d3818 mobCapCalculator, // This is the key fix - was previously null level.paperConfig().entities.spawning.perPlayerMobSpawns ); -@@ -627,9 +627,32 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -627,9 +627,23 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) Util.shuffle(list, this.shuffleRandom); // Paper - Optional per player mob spawns; do not need this when per-player is enabled // Paper end - chunk tick iteration optimisation @@ -56,16 +56,7 @@ index 46e171ca454253c32e22c0c18587e9a7ba19f331..fd7f38558a598192703a8d79fc4d3818 + // Leaf start + var lastSpawnState1 = lastSpawnState; + if ((!org.dreeam.leaf.config.modules.async.AsyncMobSpawning.enabled || _pufferfish_spawnCountsReady.get()) && lastSpawnState1 != null) { -+ if (!lastSpawnState1.playerCap.isEmpty()) { -+ for (final var iterator = lastSpawnState1.playerCap.reference2ReferenceEntrySet().fastIterator(); iterator.hasNext(); ) { -+ final var entry = iterator.next(); -+ final var entryKey = entry.getKey().mobCounts; -+ final var entryVal = entry.getValue(); -+ for (int i = 0; i < ServerPlayer.MOBCATEGORY_TOTAL_ENUMS; i++) { -+ entryKey[i] += entryVal[i]; -+ } -+ } -+ } ++ lastSpawnState1.applyPerPlayerMobCount(level); + if (list instanceof it.unimi.dsi.fastutil.objects.ReferenceArrayList arrayList) { + LevelChunk[] levelChunks = arrayList.elements(); + int size = arrayList.size(); @@ -83,7 +74,7 @@ index 46e171ca454253c32e22c0c18587e9a7ba19f331..fd7f38558a598192703a8d79fc4d3818 list.clear(); } diff --git a/net/minecraft/world/level/NaturalSpawner.java b/net/minecraft/world/level/NaturalSpawner.java -index f242941ce06d356a025e306efe78c688e9b755c4..8d50517a4c6c4f14dcb14ea18904749f7bebabf0 100644 +index f242941ce06d356a025e306efe78c688e9b755c4..ee38a26fd1d9b8d8718a16af4fe019645606a956 100644 --- a/net/minecraft/world/level/NaturalSpawner.java +++ b/net/minecraft/world/level/NaturalSpawner.java @@ -1,5 +1,7 @@ @@ -102,12 +93,12 @@ index f242941ce06d356a025e306efe78c688e9b755c4..8d50517a4c6c4f14dcb14ea18904749f public static NaturalSpawner.SpawnState createState( int spawnableChunkCount, Iterable entities, NaturalSpawner.ChunkGetter chunkGetter, LocalMobCapCalculator calculator, final boolean countMobs ) { -@@ -108,7 +111,61 @@ public final class NaturalSpawner { +@@ -108,7 +111,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.objects.Reference2ReferenceOpenHashMap<>()); ++ return new NaturalSpawner.SpawnState(spawnableChunkCount, map, potentialCalculator, calculator, new it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap<>()); // Leaf + } + + public static NaturalSpawner.SpawnState createState1( @@ -116,7 +107,7 @@ index f242941ce06d356a025e306efe78c688e9b755c4..8d50517a4c6c4f14dcb14ea18904749f + // Paper end - Optional per player mob spawns + PotentialCalculator potentialCalculator = new PotentialCalculator(); + Object2IntOpenHashMap map = new Object2IntOpenHashMap<>(); -+ it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap playerCap = new it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap<>(); ++ it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap 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()))) { @@ -144,6 +135,9 @@ index f242941ce06d356a025e306efe78c688e9b755c4..8d50517a4c6c4f14dcb14ea18904749f + // Paper start - Optional per player mob spawns + if (countMobs) { + final int index = entity.getType().getCategory().ordinal(); ++ ++chunkCap.computeIfAbsent(chunk.getPos().longKey, 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; @@ -155,17 +149,18 @@ index f242941ce06d356a025e306efe78c688e9b755c4..8d50517a4c6c4f14dcb14ea18904749f + 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, calculator, playerCap); ++ return new NaturalSpawner.SpawnState(spawnableChunkCount, map, potentialCalculator, calculator, chunkCap); } static Biome getRoughBiome(BlockPos pos, ChunkAccess chunk) { -@@ -265,28 +322,67 @@ public final class NaturalSpawner { +@@ -265,28 +326,67 @@ public final class NaturalSpawner { MobCategory category, ServerLevel level, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback, final int maxSpawns, final @Nullable Consumer trackEntity, final boolean nothing // Paper end - throttle failed spawn attempts ) { @@ -241,7 +236,7 @@ index f242941ce06d356a025e306efe78c688e9b755c4..8d50517a4c6c4f14dcb14ea18904749f mutableBlockPos.set(x, y, z); double d = x + 0.5; double d1 = z + 0.5; -@@ -295,8 +391,8 @@ public final class NaturalSpawner { +@@ -295,8 +395,8 @@ public final class NaturalSpawner { double d2 = nearestPlayer.distanceToSqr(d, y, d1); if (level.isLoadedAndInBounds(mutableBlockPos) && isRightDistanceToPlayerAndSpawnPoint(level, chunk, mutableBlockPos, d2)) { // Paper - don't load chunks for mob spawn if (spawnerData == null) { @@ -252,7 +247,7 @@ index f242941ce06d356a025e306efe78c688e9b755c4..8d50517a4c6c4f14dcb14ea18904749f ); if (randomSpawnMobAt.isEmpty()) { break; -@@ -307,7 +403,7 @@ public final class NaturalSpawner { +@@ -307,7 +407,7 @@ public final class NaturalSpawner { } // Paper start - PreCreatureSpawnEvent @@ -261,7 +256,7 @@ index f242941ce06d356a025e306efe78c688e9b755c4..8d50517a4c6c4f14dcb14ea18904749f // Paper start - per player mob count backoff if (doSpawning == PreSpawnStatus.ABORT || doSpawning == PreSpawnStatus.CANCELLED) { level.getChunkSource().chunkMap.updateFailurePlayerMobTypeMap(mutableBlockPos.getX() >> 4, mutableBlockPos.getZ() >> 4, category); -@@ -414,6 +510,44 @@ public final class NaturalSpawner { +@@ -414,6 +514,44 @@ public final class NaturalSpawner { && level.noCollision(entityType.getSpawnAABB(pos.getX() + 0.5, pos.getY(), pos.getZ() + 0.5)); return success ? PreSpawnStatus.SUCCESS : PreSpawnStatus.FAIL; // Paper - PreCreatureSpawnEvent } @@ -306,7 +301,7 @@ index f242941ce06d356a025e306efe78c688e9b755c4..8d50517a4c6c4f14dcb14ea18904749f @Nullable private static Mob getMobForSpawn(ServerLevel level, EntityType entityType) { -@@ -449,6 +583,17 @@ public final class NaturalSpawner { +@@ -449,6 +587,17 @@ public final class NaturalSpawner { : mobsAt(level, structureManager, generator, category, pos, biome).getRandom(random); } @@ -324,7 +319,7 @@ index f242941ce06d356a025e306efe78c688e9b755c4..8d50517a4c6c4f14dcb14ea18904749f private static boolean canSpawnMobAt( ServerLevel level, StructureManager structureManager, ChunkGenerator generator, MobCategory category, MobSpawnSettings.SpawnerData data, BlockPos pos ) { -@@ -463,6 +608,16 @@ public final class NaturalSpawner { +@@ -463,6 +612,16 @@ public final class NaturalSpawner { : generator.getMobsAt(biome != null ? biome : (org.dreeam.leaf.config.modules.opt.OptimizeBiome.mobSpawn ? level.getBiomeCached(pos) : level.getBiome(pos)), structureManager, cetagory, pos); // Leaf - cache getBiome } @@ -341,7 +336,7 @@ index f242941ce06d356a025e306efe78c688e9b755c4..8d50517a4c6c4f14dcb14ea18904749f public static boolean isInNetherFortressBounds(BlockPos pos, ServerLevel level, MobCategory category, StructureManager structureManager) { if (category == MobCategory.MONSTER && level.getBlockState(pos.below()).is(Blocks.NETHER_BRICKS)) { Structure structure = structureManager.registryAccess().lookupOrThrow(Registries.STRUCTURE).getValue(BuiltinStructures.FORTRESS); -@@ -472,6 +627,28 @@ public final class NaturalSpawner { +@@ -472,6 +631,28 @@ public final class NaturalSpawner { } } @@ -370,11 +365,11 @@ index f242941ce06d356a025e306efe78c688e9b755c4..8d50517a4c6c4f14dcb14ea18904749f private static BlockPos getRandomPosWithin(Level level, LevelChunk chunk) { ChunkPos pos = chunk.getPos(); int i = pos.getMinBlockX() + level.random.nextInt(16); -@@ -612,18 +789,21 @@ public final class NaturalSpawner { +@@ -612,18 +793,21 @@ public final class NaturalSpawner { @Nullable private EntityType lastCheckedType; private double lastCharge; -+ public final it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap playerCap; // Leaf ++ public final it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap playerCap; // Leaf SpawnState( int spawnableChunkCount, @@ -382,17 +377,48 @@ index f242941ce06d356a025e306efe78c688e9b755c4..8d50517a4c6c4f14dcb14ea18904749f PotentialCalculator spawnPotential, - LocalMobCapCalculator localMobCapCalculator + LocalMobCapCalculator localMobCapCalculator, -+ it.unimi.dsi.fastutil.objects.Reference2ReferenceOpenHashMap playerCap ++ it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap playerCap // Leaf ) { this.spawnableChunkCount = spawnableChunkCount; this.mobCategoryCounts = mobCategoryCounts; this.spawnPotential = spawnPotential; this.localMobCapCalculator = localMobCapCalculator; this.unmodifiableMobCategoryCounts = Object2IntMaps.unmodifiable(mobCategoryCounts); -+ this.playerCap = playerCap; ++ this.playerCap = playerCap; // Leaf } private boolean canSpawn(EntityType entityType, BlockPos pos, ChunkAccess chunk) { +@@ -680,5 +864,30 @@ public final class NaturalSpawner { + boolean canSpawnForCategoryLocal(MobCategory category, ChunkPos chunkPos) { + return this.localMobCapCalculator.canSpawn(category, chunkPos); + } ++ ++ // Leaf start ++ public void applyPerPlayerMobCount(ServerLevel level) { ++ if (playerCap.isEmpty()) { ++ return; ++ } ++ final var iterator = playerCap.long2ObjectEntrySet().fastIterator(); ++ final var nearbyPlayers = level.moonrise$getNearbyPlayers(); ++ while (iterator.hasNext()) { ++ final var entry = iterator.next(); ++ final long chunk = entry.getLongKey(); ++ final int[] cap = entry.getValue(); ++ var players = nearbyPlayers.getPlayersByChunk(ChunkPos.getX(chunk), ChunkPos.getZ(chunk), ca.spottedleaf.moonrise.common.misc.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE); ++ if (players == null) continue; ++ int playersSize = players.size(); ++ var 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 + } + } diff --git a/net/minecraft/world/level/StructureManager.java b/net/minecraft/world/level/StructureManager.java index fbe93098ce0366054a6da857cd808af1431b6612..a7cadf708bd79abb96fed0d41b4dbc00b265a9a6 100644 --- a/net/minecraft/world/level/StructureManager.java diff --git a/leaf-server/minecraft-patches/features/0265-throttle-mob-spawning.patch b/leaf-server/minecraft-patches/features/0265-throttle-mob-spawning.patch index dbc89401..b65bc7d6 100644 --- a/leaf-server/minecraft-patches/features/0265-throttle-mob-spawning.patch +++ b/leaf-server/minecraft-patches/features/0265-throttle-mob-spawning.patch @@ -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 -index 8d50517a4c6c4f14dcb14ea18904749f7bebabf0..896868b34ba5ec76be693aca1c3b75c2afbcc72e 100644 +index ee38a26fd1d9b8d8718a16af4fe019645606a956..0d587e160cb1d55fe7bc23f8ab3c3cdb48e98759 100644 --- a/net/minecraft/world/level/NaturalSpawner.java +++ b/net/minecraft/world/level/NaturalSpawner.java -@@ -211,6 +211,17 @@ public final class NaturalSpawner { +@@ -215,6 +215,17 @@ public final class NaturalSpawner { // Paper start - Optional per player mob spawns final boolean canSpawn; int maxSpawns = Integer.MAX_VALUE; diff --git a/leaf-server/minecraft-patches/features/0270-optimize-random-tick.patch b/leaf-server/minecraft-patches/features/0270-optimize-random-tick.patch index e88f11e5..38eb1d4d 100644 --- a/leaf-server/minecraft-patches/features/0270-optimize-random-tick.patch +++ b/leaf-server/minecraft-patches/features/0270-optimize-random-tick.patch @@ -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 -index fd7f38558a598192703a8d79fc4d3818abb2551c..f2fccba5ce54cfed9ac76555e8d2860a3070fe1c 100644 +index 51b4a043c09eef84bf926ea02bf588e9ce900788..8ca23e74011b70a8524fb62d1acd4344c3e71eb8 100644 --- a/net/minecraft/server/level/ServerChunkCache.java +++ b/net/minecraft/server/level/ServerChunkCache.java -@@ -657,7 +657,13 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon +@@ -648,7 +648,13 @@ public class ServerChunkCache extends ChunkSource implements ca.spottedleaf.moon list.clear(); }