Paper/patches/server/0987-Optional-per-player-mob-spawns.patch

256 Zeilen
16 KiB
Diff

2021-06-11 14:02:28 +02:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: kickash32 <kickash32@gmail.com>
Date: Mon, 19 Aug 2019 01:27:58 +0500
Subject: [PATCH] Optional per player mob spawns
2021-06-14 04:41:44 +02:00
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java
index 1d2d4d38ff3414896d07f7f4e40d0edb9a8c3993..56f855ed9dbbb9a7025bef6f9e98a8cdcf2ad4fc 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/level/ChunkMap.java
+++ b/src/main/java/net/minecraft/server/level/ChunkMap.java
2024-04-25 11:42:10 +02:00
@@ -291,9 +291,28 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider
Rewrite chunk system (#8177) Patch documentation to come Issues with the old system that are fixed now: - World generation does not scale with cpu cores effectively. - Relies on the main thread for scheduling and maintaining chunk state, dropping chunk load/generate rates at lower tps. - Unreliable prioritisation of chunk gen/load calls that block the main thread. - Shutdown logic is utterly unreliable, as it has to wait for all chunks to unload - is it guaranteed that the chunk system is in a state on shutdown that it can reliably do this? Watchdog shutdown also typically failed due to thread checks, which is now resolved. - Saving of data is not unified (i.e can save chunk data without saving entity data, poses problems for desync if shutdown is really abnormal. - Entities are not loaded with chunks. This caused quite a bit of headache for Chunk#getEntities API, but now the new chunk system loads entities with chunks so that they are ready whenever the chunk loads in. Effectively brings the behavior back to 1.16 era, but still storing entities in their own separate regionfiles. The above list is not complete. The patch documentation will complete it. New chunk system hard relies on starlight and dataconverter, and most importantly the new concurrent utilities in ConcurrentUtil. Some of the old async chunk i/o interface (i.e the old file io thread reroutes _some_ calls to the new file io thread) is kept for plugin compat reasons. It will be removed in the next major version of minecraft. The old legacy chunk system patches have been moved to the removed folder in case we need them again.
2022-09-26 10:02:51 +02:00
});
}
Rewrite chunk system (#8177) Patch documentation to come Issues with the old system that are fixed now: - World generation does not scale with cpu cores effectively. - Relies on the main thread for scheduling and maintaining chunk state, dropping chunk load/generate rates at lower tps. - Unreliable prioritisation of chunk gen/load calls that block the main thread. - Shutdown logic is utterly unreliable, as it has to wait for all chunks to unload - is it guaranteed that the chunk system is in a state on shutdown that it can reliably do this? Watchdog shutdown also typically failed due to thread checks, which is now resolved. - Saving of data is not unified (i.e can save chunk data without saving entity data, poses problems for desync if shutdown is really abnormal. - Entities are not loaded with chunks. This caused quite a bit of headache for Chunk#getEntities API, but now the new chunk system loads entities with chunks so that they are ready whenever the chunk loads in. Effectively brings the behavior back to 1.16 era, but still storing entities in their own separate regionfiles. The above list is not complete. The patch documentation will complete it. New chunk system hard relies on starlight and dataconverter, and most importantly the new concurrent utilities in ConcurrentUtil. Some of the old async chunk i/o interface (i.e the old file io thread reroutes _some_ calls to the new file io thread) is kept for plugin compat reasons. It will be removed in the next major version of minecraft. The old legacy chunk system patches have been moved to the removed folder in case we need them again.
2022-09-26 10:02:51 +02:00
+ // Paper start - Optional per player mob spawns
+ public void updatePlayerMobTypeMap(final Entity entity) {
+ if (!this.level.paperConfig().entities.spawning.perPlayerMobSpawns) {
2021-06-11 14:02:28 +02:00
+ return;
+ }
2021-06-14 04:41:44 +02:00
+ int index = entity.getType().getCategory().ordinal();
2021-06-11 14:02:28 +02:00
+
+ final com.destroystokyo.paper.util.maplist.ReferenceList<ServerPlayer> inRange =
+ this.getNearbyPlayers().getPlayers(entity.chunkPosition(), io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
+ if (inRange == null) {
+ return;
+ }
+ final Object[] backingSet = inRange.getRawData();
+ for (int i = 0, len = inRange.size(); i < len; i++) {
+ ++((ServerPlayer)backingSet[i]).mobCounts[index];
2021-06-11 14:02:28 +02:00
+ }
+ }
+
public int getMobCountNear(final ServerPlayer player, final net.minecraft.world.entity.MobCategory mobCategory) {
- return -1;
+ return player.mobCounts[mobCategory.ordinal()];
}
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
private static double euclideanDistanceSquared(ChunkPos pos, Entity entity) {
2021-06-14 04:41:44 +02:00
double d0 = (double) SectionPos.sectionToBlockCoord(pos.x, 8);
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/server/level/ServerChunkCache.java b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
2024-04-25 11:42:10 +02:00
index d1728e13a7b649f308bde90ab633c79d86c10822..002aad174fb1781ee963414037f84e5120488592 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/level/ServerChunkCache.java
+++ b/src/main/java/net/minecraft/server/level/ServerChunkCache.java
2024-04-25 11:42:10 +02:00
@@ -516,7 +516,19 @@ public class ServerChunkCache extends ChunkSource {
2023-12-05 23:32:41 +01:00
gameprofilerfiller.popPush("naturalSpawnCount");
this.level.timings.countNaturalMobs.startTiming(); // Paper - timings
int k = this.distanceManager.getNaturalSpawnChunkCount();
- NaturalSpawner.SpawnState spawnercreature_d = NaturalSpawner.createState(k, this.level.getAllEntities(), this::getFullChunk, new LocalMobCapCalculator(this.chunkMap));
+ // Paper start - Optional per player mob spawns
2023-12-05 23:32:41 +01:00
+ int naturalSpawnChunkCount = k;
+ NaturalSpawner.SpawnState spawnercreature_d; // moved down
+ 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) {
+ Arrays.fill(player.mobCounts, 0);
+ }
+ spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, null, true);
+ } else {
+ spawnercreature_d = NaturalSpawner.createState(naturalSpawnChunkCount, this.level.getAllEntities(), this::getFullChunk, !this.level.paperConfig().entities.spawning.perPlayerMobSpawns ? new LocalMobCapCalculator(this.chunkMap) : null, false);
2021-06-11 14:02:28 +02:00
+ }
+ // Paper end - Optional per player mob spawns
2023-12-05 23:32:41 +01:00
this.level.timings.countNaturalMobs.stopTiming(); // Paper - timings
2021-06-11 14:02:28 +02:00
2023-12-05 23:32:41 +01:00
this.lastSpawnState = spawnercreature_d;
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/server/level/ServerPlayer.java b/src/main/java/net/minecraft/server/level/ServerPlayer.java
Updated Upstream (Bukkit/CraftBukkit) (#10691) Updated Upstream (Bukkit/CraftBukkit) Upstream has released updates that appear to apply and compile correctly. This update has not been tested by PaperMC and as with ANY update, please do your own testing Bukkit Changes: fa99e752 PR-1007: Add ItemMeta#getAsComponentString() 94a91782 Fix copy-pasted BlockType.Typed documentation 9b34ac8c Largely restore deprecated PotionData API 51a6449b PR-1008: Deprecate ITEMS_TOOLS, removed in 1.20.5 702d15fe Fix Javadoc reference 42f6cdf4 PR-919: Add internal ItemType and BlockType, delegate Material methods to them 237bb37b SPIGOT-1166, SPIGOT-7647: Expose Damager BlockState in EntityDamageByBlockEvent 035ea146 SPIGOT-6993: Allow #setVelocity to change the speed of a fireball and add a note to #setDirection about it 8c7880fb PR-1004: Improve field rename handling and centralize conversion between bukkit and string more 87c90e93 SPIGOT-7650: Add DamageSource for EntityDeathEvent and PlayerDeathEvent CraftBukkit Changes: 4af0f22e8 SPIGOT-7664: Item meta should prevail over block states c2ccc46ec SPIGOT-7666: Fix access to llama and horse special slot 124ac66d7 SPIGOT-7665: Fix ThrownPotion#getEffects() implementation only bringing custom effects 66f1f439a Restore null page behaviour of signed books even though not strictly allowed by API 6118e5398 Fix regression listening to minecraft:brand custom payloads c1a26b366 Fix unnecessary and potential not thread-safe chat visibility check 12360a7ec Remove unused imports 147b098b4 PR-1397: Add ItemMeta#getAsComponentString() 428aefe0e Largely restore deprecated PotionData API afe5b5ee9 PR-1275: Add internal ItemType and BlockType, delegate Material methods to them 8afeafa7d SPIGOT-1166, SPIGOT-7647: Expose Damager BlockState in EntityDamageByBlockEvent 4e7d749d4 SPIGOT-6993: Allow #setVelocity to change the speed of a fireball and add a note to #setDirection about it 441880757 Support both entity_data and bucket_entity_data on axolotl/fish buckets 0e22fdd1e Fix custom direct BlockState being not correctly set in DamageSource f2182ed47 SPIGOT-7659: TropicalFishBucketMeta should use BUCKET_ENTITY_DATA 2a6207fe1 PR-1393: Improve field rename handling and centralize conversion between bukkit and string more c024a5039 SPIGOT-7650: Add DamageSource for EntityDeathEvent and PlayerDeathEvent 741b84480 PR-1390: Improve internal handling of damage sources 0364df4e1 SPIGOT-7657: Error when loading angry entities
2024-05-11 23:48:37 +02:00
index 467ef6237e11b9d28f5d7ebf9dc56723d756e5ba..7626872528cddd3e3b9a895a77a2ceca50bdb452 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/server/level/ServerPlayer.java
+++ b/src/main/java/net/minecraft/server/level/ServerPlayer.java
@@ -272,6 +272,10 @@ public class ServerPlayer extends Player {
public boolean queueHealthUpdatePacket;
2021-06-11 14:02:28 +02:00
public net.minecraft.network.protocol.game.ClientboundSetHealthPacket queuedHealthUpdatePacket;
// Paper end - cancellable death event
+ // Paper start - Optional per player mob spawns
+ public static final int MOBCATEGORY_TOTAL_ENUMS = net.minecraft.world.entity.MobCategory.values().length;
+ public final int[] mobCounts = new int[MOBCATEGORY_TOTAL_ENUMS]; // Paper
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
// CraftBukkit start
2024-04-25 11:42:10 +02:00
public CraftPlayer.TransferCookieConnection transferCookieConnection;
2021-06-11 14:02:28 +02:00
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
2024-04-25 11:42:10 +02:00
index ea6533c1ac218aa075da3401807a06fcb7892321..0679636530ca1afd077c43b0fa605a2ac74e0522 100644
2021-06-11 14:02:28 +02:00
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
2024-04-25 11:42:10 +02:00
@@ -67,6 +67,12 @@ public final class NaturalSpawner {
2021-06-14 04:41:44 +02:00
private NaturalSpawner() {}
2022-11-12 21:57:41 +01:00
public static NaturalSpawner.SpawnState createState(int spawningChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkSource, LocalMobCapCalculator densityCapper) {
+ // Paper start - Optional per player mob spawns
2022-11-12 21:57:41 +01:00
+ return createState(spawningChunkCount, entities, chunkSource, densityCapper, false);
2021-06-11 14:02:28 +02:00
+ }
+
2022-11-12 21:57:41 +01:00
+ public static NaturalSpawner.SpawnState createState(int spawningChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkSource, LocalMobCapCalculator densityCapper, boolean countMobs) {
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
PotentialCalculator spawnercreatureprobabilities = new PotentialCalculator();
Object2IntOpenHashMap<MobCategory> object2intopenhashmap = new Object2IntOpenHashMap();
2021-06-14 04:41:44 +02:00
Iterator iterator = entities.iterator();
2024-04-25 11:42:10 +02:00
@@ -99,11 +105,16 @@ public final class NaturalSpawner {
2023-03-14 20:54:57 +01:00
spawnercreatureprobabilities.addCharge(entity.blockPosition(), biomesettingsmobs_b.charge());
}
- if (entity instanceof Mob) {
+ if (densityCapper != null && entity instanceof Mob) { // Paper - Optional per player mob spawns
2022-11-12 21:57:41 +01:00
densityCapper.addMob(chunk.getPos(), enumcreaturetype);
2021-06-11 14:02:28 +02:00
}
object2intopenhashmap.addTo(enumcreaturetype, 1);
+ // Paper start - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
+ if (countMobs) {
2021-06-14 04:41:44 +02:00
+ chunk.level.getChunkSource().chunkMap.updatePlayerMobTypeMap(entity);
2021-06-11 14:02:28 +02:00
+ }
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
});
}
}
2024-04-25 11:42:10 +02:00
@@ -138,13 +149,35 @@ public final class NaturalSpawner {
2021-06-11 14:02:28 +02:00
continue;
}
- if ((spawnAnimals || !enumcreaturetype.isFriendly()) && (spawnMonsters || enumcreaturetype.isFriendly()) && (rareSpawn || !enumcreaturetype.isPersistent()) && info.canSpawnForCategory(enumcreaturetype, chunk.getPos(), limit)) {
+ // Paper start - Optional per player mob spawns; only allow spawns upto the limit per chunk and update count afterwards
2021-06-14 06:29:25 +02:00
+ int currEntityCount = info.mobCategoryCounts.getInt(enumcreaturetype);
2021-06-14 04:41:44 +02:00
+ int k1 = limit * info.getSpawnableChunkCount() / NaturalSpawner.MAGIC_NUMBER;
2021-06-11 14:02:28 +02:00
+ int difference = k1 - currEntityCount;
+
+ if (world.paperConfig().entities.spawning.perPlayerMobSpawns) {
2021-06-11 14:02:28 +02:00
+ int minDiff = Integer.MAX_VALUE;
+ final com.destroystokyo.paper.util.maplist.ReferenceList<net.minecraft.server.level.ServerPlayer> inRange =
+ world.chunkSource.chunkMap.getNearbyPlayers().getPlayers(chunk.getPos(), io.papermc.paper.util.player.NearbyPlayers.NearbyMapType.TICK_VIEW_DISTANCE);
+ if (inRange != null) {
+ final Object[] backingSet = inRange.getRawData();
+ for (int k = 0, len = inRange.size(); k < len; k++) {
+ minDiff = Math.min(limit - world.getChunkSource().chunkMap.getMobCountNear((net.minecraft.server.level.ServerPlayer)backingSet[k], enumcreaturetype), minDiff);
+ }
2021-06-11 14:02:28 +02:00
+ }
+ difference = (minDiff == Integer.MAX_VALUE) ? 0 : minDiff;
+ }
+ if ((spawnAnimals || !enumcreaturetype.isFriendly()) && (spawnMonsters || enumcreaturetype.isFriendly()) && (rareSpawn || !enumcreaturetype.isPersistent()) && difference > 0) {
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
// CraftBukkit end
2021-06-14 04:41:44 +02:00
Objects.requireNonNull(info);
NaturalSpawner.SpawnPredicate spawnercreature_c = info::canSpawn;
Objects.requireNonNull(info);
- NaturalSpawner.spawnCategoryForChunk(enumcreaturetype, world, chunk, spawnercreature_c, info::afterSpawn);
+ // Paper start - Optional per player mob spawns
2021-06-14 04:41:44 +02:00
+ int spawnCount = NaturalSpawner.spawnCategoryForChunk(enumcreaturetype, world, chunk, spawnercreature_c, info::afterSpawn,
+ difference, world.paperConfig().entities.spawning.perPlayerMobSpawns ? world.getChunkSource().chunkMap::updatePlayerMobTypeMap : null);
2021-06-14 06:29:25 +02:00
+ info.mobCategoryCounts.mergeInt(enumcreaturetype, spawnCount, Integer::sum);
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
}
2024-04-25 11:42:10 +02:00
@@ -163,11 +196,17 @@ public final class NaturalSpawner {
// Paper end - Add mobcaps commands
2021-06-11 14:02:28 +02:00
public static void spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) {
+ // Paper start - Optional per player mob spawns
+ spawnCategoryForChunk(group, world, chunk, checker, runner, Integer.MAX_VALUE, null);
2021-06-11 14:02:28 +02:00
+ }
2021-06-14 04:41:44 +02:00
+ public static int spawnCategoryForChunk(MobCategory group, ServerLevel world, LevelChunk chunk, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner, int maxSpawns, Consumer<Entity> trackEntity) {
+ // Paper end - Optional per player mob spawns
2021-06-14 04:41:44 +02:00
BlockPos blockposition = NaturalSpawner.getRandomPosWithin(world, chunk);
2021-06-11 14:02:28 +02:00
2021-06-14 04:41:44 +02:00
if (blockposition.getY() >= world.getMinBuildHeight() + 1) {
- NaturalSpawner.spawnCategoryForPosition(group, world, chunk, blockposition, checker, runner);
+ return NaturalSpawner.spawnCategoryForPosition(group, world, chunk, blockposition, checker, runner, maxSpawns, trackEntity); // Paper - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
+ return 0; // Paper - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
2021-06-14 04:41:44 +02:00
@VisibleForDebug
2024-04-25 11:42:10 +02:00
@@ -178,15 +217,21 @@ public final class NaturalSpawner {
2021-06-14 04:41:44 +02:00
});
}
+ // Paper start - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
public static void spawnCategoryForPosition(MobCategory group, ServerLevel world, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner) {
+ spawnCategoryForPosition(group, world,chunk, pos, checker, runner, Integer.MAX_VALUE, null);
2021-06-11 14:02:28 +02:00
+ }
2021-06-14 04:41:44 +02:00
+ public static int spawnCategoryForPosition(MobCategory group, ServerLevel world, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate checker, NaturalSpawner.AfterSpawnCallback runner, int maxSpawns, Consumer<Entity> trackEntity) {
+ // Paper end - Optional per player mob spawns
2022-06-08 06:06:41 +02:00
StructureManager structuremanager = world.structureManager();
2021-06-14 04:41:44 +02:00
ChunkGenerator chunkgenerator = world.getChunkSource().getGenerator();
int i = pos.getY();
BlockState iblockdata = world.getBlockStateIfLoadedAndInBounds(pos); // Paper - don't load chunks for mob spawn
+ int j = 0; // Paper - Optional per player mob spawns; moved up
2021-06-14 04:41:44 +02:00
if (iblockdata != null && !iblockdata.isRedstoneConductor(chunk, pos)) { // Paper - don't load chunks for mob spawn
2021-06-11 14:02:28 +02:00
BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
- int j = 0;
+ //int j = 0; // Paper - Optional per player mob spawns; moved up
2021-06-11 14:02:28 +02:00
int k = 0;
while (k < 3) {
2024-04-25 11:42:10 +02:00
@@ -228,14 +273,14 @@ public final class NaturalSpawner {
// Paper start - PreCreatureSpawnEvent
PreSpawnStatus doSpawning = isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2);
if (doSpawning == PreSpawnStatus.ABORT) {
2021-06-14 08:45:29 +02:00
- return;
+ return j; // Paper - Optional per player mob spawns
2021-06-14 08:45:29 +02:00
}
if (doSpawning == PreSpawnStatus.SUCCESS && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) {
// Paper end - PreCreatureSpawnEvent
2021-06-14 04:41:44 +02:00
Mob entityinsentient = NaturalSpawner.getMobForSpawn(world, biomesettingsmobs_c.type);
2021-06-11 14:02:28 +02:00
if (entityinsentient == null) {
- return;
+ return j; // Paper - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
2021-06-14 04:41:44 +02:00
entityinsentient.moveTo(d0, (double) i, d1, world.random.nextFloat() * 360.0F, 0.0F);
2024-04-25 11:42:10 +02:00
@@ -248,10 +293,15 @@ public final class NaturalSpawner {
2021-06-14 04:41:44 +02:00
++j;
2021-06-11 14:02:28 +02:00
++k1;
2021-06-14 04:41:44 +02:00
runner.run(entityinsentient, chunk);
+ // Paper start - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
+ if (trackEntity != null) {
+ trackEntity.accept(entityinsentient);
+ }
+ // Paper end - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
// CraftBukkit end
- if (j >= entityinsentient.getMaxSpawnClusterSize()) {
- return;
+ if (j >= entityinsentient.getMaxSpawnClusterSize() || j >= maxSpawns) { // Paper - Optional per player mob spawns
+ return j; // Paper - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
if (entityinsentient.isMaxGroupSizeReached(k1)) {
2024-04-25 11:42:10 +02:00
@@ -273,6 +323,7 @@ public final class NaturalSpawner {
2021-06-11 14:02:28 +02:00
}
}
+ return j; // Paper - Optional per player mob spawns
2021-06-11 14:02:28 +02:00
}
private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel world, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double squaredDistance) {
2024-04-25 11:42:10 +02:00
@@ -523,7 +574,7 @@ public final class NaturalSpawner {
MobCategory enumcreaturetype = entitytypes.getCategory();
this.mobCategoryCounts.addTo(enumcreaturetype, 1);
- this.localMobCapCalculator.addMob(new ChunkPos(blockposition), enumcreaturetype);
+ if (this.localMobCapCalculator != null) this.localMobCapCalculator.addMob(new ChunkPos(blockposition), enumcreaturetype); // Paper - Optional per player mob spawns
}
public int getSpawnableChunkCount() {
2024-04-25 11:42:10 +02:00
@@ -539,6 +590,7 @@ public final class NaturalSpawner {
int i = limit * this.spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER;
// CraftBukkit end
+ if (this.localMobCapCalculator == null) return this.mobCategoryCounts.getInt(enumcreaturetype) < i; // Paper - Optional per player mob spawns
return this.mobCategoryCounts.getInt(enumcreaturetype) >= i ? false : this.localMobCapCalculator.canSpawn(enumcreaturetype, chunkcoordintpair);
}
}