--- a/net/minecraft/world/level/SpawnerCreature.java +++ b/net/minecraft/world/level/SpawnerCreature.java @@ -47,6 +47,11 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; +// CraftBukkit start +import net.minecraft.world.level.storage.WorldData; +import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; +// CraftBukkit end + public final class SpawnerCreature { private static final Logger LOGGER = LogManager.getLogger(); @@ -73,7 +78,8 @@ if (entity instanceof EntityInsentient) { EntityInsentient entityinsentient = (EntityInsentient) entity; - if (entityinsentient.isPersistent() || entityinsentient.isSpecialPersistence()) { + // CraftBukkit - Split out persistent check, don't apply it to special persistent mobs + if (entityinsentient.isTypeNotPersistent(0) && entityinsentient.isPersistent()) { continue; } } @@ -108,10 +114,54 @@ EnumCreatureType[] aenumcreaturetype = SpawnerCreature.SPAWNING_CATEGORIES; int i = aenumcreaturetype.length; + // CraftBukkit start - Other mob type spawn tick rate + WorldData worlddata = worldserver.getWorldData(); + boolean spawnAnimalThisTick = worldserver.ticksPerAnimalSpawns != 0L && worlddata.getTime() % worldserver.ticksPerAnimalSpawns == 0L; + boolean spawnMonsterThisTick = worldserver.ticksPerMonsterSpawns != 0L && worlddata.getTime() % worldserver.ticksPerMonsterSpawns == 0L; + boolean spawnWaterThisTick = worldserver.ticksPerWaterSpawns != 0L && worlddata.getTime() % worldserver.ticksPerWaterSpawns == 0L; + boolean spawnAmbientThisTick = worldserver.ticksPerAmbientSpawns != 0L && worlddata.getTime() % worldserver.ticksPerAmbientSpawns == 0L; + boolean spawnWaterAmbientThisTick = worldserver.ticksPerWaterAmbientSpawns != 0L && worlddata.getTime() % worldserver.ticksPerWaterAmbientSpawns == 0L; + boolean spawnWaterUndergroundCreatureThisTick = worldserver.ticksPerWaterUndergroundCreatureSpawns != 0L && worlddata.getTime() % worldserver.ticksPerWaterUndergroundCreatureSpawns == 0L; + // CraftBukkit end + for (int j = 0; j < i; ++j) { EnumCreatureType enumcreaturetype = aenumcreaturetype[j]; + // CraftBukkit start - Use per-world spawn limits + boolean spawnThisTick = true; + int limit = enumcreaturetype.b(); + switch (enumcreaturetype) { + case MONSTER: + spawnThisTick = spawnMonsterThisTick; + limit = worldserver.getWorld().getMonsterSpawnLimit(); + break; + case CREATURE: + spawnThisTick = spawnAnimalThisTick; + limit = worldserver.getWorld().getAnimalSpawnLimit(); + break; + case WATER_CREATURE: + spawnThisTick = spawnWaterThisTick; + limit = worldserver.getWorld().getWaterAnimalSpawnLimit(); + break; + case UNDERGROUND_WATER_CREATURE: + spawnThisTick = spawnWaterUndergroundCreatureThisTick; + limit = worldserver.getWorld().getWaterUndergroundCreatureSpawnLimit(); + break; + case AMBIENT: + spawnThisTick = spawnAmbientThisTick; + limit = worldserver.getWorld().getAmbientSpawnLimit(); + break; + case WATER_AMBIENT: + spawnThisTick = spawnWaterAmbientThisTick; + limit = worldserver.getWorld().getWaterAmbientSpawnLimit(); + break; + } - if ((flag || !enumcreaturetype.d()) && (flag1 || enumcreaturetype.d()) && (flag2 || !enumcreaturetype.e()) && spawnercreature_d.a(enumcreaturetype)) { + if (!spawnThisTick || limit == 0) { + continue; + } + + if ((flag || !enumcreaturetype.d()) && (flag1 || enumcreaturetype.d()) && (flag2 || !enumcreaturetype.e()) && spawnercreature_d.a(enumcreaturetype, limit)) { + // CraftBukkit end Objects.requireNonNull(spawnercreature_d); SpawnerCreature.c spawnercreature_c = spawnercreature_d::a; @@ -196,10 +246,14 @@ entityinsentient.setPositionRotation(d0, (double) i, d1, worldserver.random.nextFloat() * 360.0F, 0.0F); if (a(worldserver, entityinsentient, d2)) { groupdataentity = entityinsentient.prepare(worldserver, worldserver.getDamageScaler(entityinsentient.getChunkCoordinates()), EnumMobSpawn.NATURAL, groupdataentity, (NBTTagCompound) null); - ++j; - ++k1; - worldserver.addAllEntities(entityinsentient); - spawnercreature_a.run(entityinsentient, ichunkaccess); + // CraftBukkit start + worldserver.addAllEntities(entityinsentient, SpawnReason.NATURAL); + if (!entityinsentient.isRemoved()) { + ++j; + ++k1; + spawnercreature_a.run(entityinsentient, ichunkaccess); + } + // CraftBukkit end if (j >= entityinsentient.getMaxSpawnGroup()) { return; } @@ -370,7 +424,7 @@ if (entityinsentient.a((GeneratorAccess) worldaccess, EnumMobSpawn.CHUNK_GENERATION) && entityinsentient.a((IWorldReader) worldaccess)) { groupdataentity = entityinsentient.prepare(worldaccess, worldaccess.getDamageScaler(entityinsentient.getChunkCoordinates()), EnumMobSpawn.CHUNK_GENERATION, groupdataentity, (NBTTagCompound) null); - worldaccess.addAllEntities(entityinsentient); + worldaccess.addAllEntities(entityinsentient, SpawnReason.CHUNK_GEN); // CraftBukkit flag = true; } } @@ -486,8 +540,10 @@ return this.unmodifiableMobCategoryCounts; } - boolean a(EnumCreatureType enumcreaturetype) { - int i = enumcreaturetype.b() * this.spawnableChunkCount / SpawnerCreature.MAGIC_NUMBER; + // CraftBukkit start + boolean a(EnumCreatureType enumcreaturetype, int limit) { + int i = limit * this.spawnableChunkCount / SpawnerCreature.MAGIC_NUMBER; + // CraftBukkit end return this.mobCategoryCounts.getInt(enumcreaturetype) < i; }