diff options
Diffstat (limited to 'patch-remap/mache-spigotflower/net/minecraft/world/level/NaturalSpawner.java.patch')
-rw-r--r-- | patch-remap/mache-spigotflower/net/minecraft/world/level/NaturalSpawner.java.patch | 676 |
1 files changed, 676 insertions, 0 deletions
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/level/NaturalSpawner.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/level/NaturalSpawner.java.patch new file mode 100644 index 0000000000..ef00c13ded --- /dev/null +++ b/patch-remap/mache-spigotflower/net/minecraft/world/level/NaturalSpawner.java.patch @@ -0,0 +1,676 @@ +--- a/net/minecraft/world/level/NaturalSpawner.java ++++ b/net/minecraft/world/level/NaturalSpawner.java +@@ -27,16 +27,16 @@ + import net.minecraft.util.random.WeightedRandomList; + import net.minecraft.world.entity.Entity; + import net.minecraft.world.entity.EntityType; ++import net.minecraft.world.entity.EnumMobSpawn; ++import net.minecraft.world.entity.GroupDataEntity; + import net.minecraft.world.entity.Mob; + import net.minecraft.world.entity.MobCategory; +-import net.minecraft.world.entity.MobSpawnType; +-import net.minecraft.world.entity.SpawnGroupData; + import net.minecraft.world.entity.SpawnPlacements; + import net.minecraft.world.entity.player.Player; + import net.minecraft.world.level.biome.Biome; + import net.minecraft.world.level.biome.MobSpawnSettings; + import net.minecraft.world.level.block.Blocks; +-import net.minecraft.world.level.block.state.BlockState; ++import net.minecraft.world.level.block.state.IBlockData; + import net.minecraft.world.level.chunk.ChunkAccess; + import net.minecraft.world.level.chunk.ChunkGenerator; + import net.minecraft.world.level.chunk.LevelChunk; +@@ -45,9 +45,14 @@ + import net.minecraft.world.level.levelgen.structure.Structure; + import net.minecraft.world.level.levelgen.structure.structures.NetherFortressStructure; + import net.minecraft.world.level.material.FluidState; +-import net.minecraft.world.level.pathfinder.PathComputationType; ++import net.minecraft.world.level.pathfinder.PathMode; ++import net.minecraft.world.level.storage.LevelData; + import net.minecraft.world.phys.Vec3; + import org.slf4j.Logger; ++import org.bukkit.craftbukkit.util.CraftSpawnCategory; ++import org.bukkit.entity.SpawnCategory; ++import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; ++// CraftBukkit end + + public final class NaturalSpawner { + +@@ -56,112 +61,127 @@ + public static final int SPAWN_DISTANCE_CHUNK = 8; + public static final int SPAWN_DISTANCE_BLOCK = 128; + static final int MAGIC_NUMBER = (int) Math.pow(17.0D, 2.0D); +- private static final MobCategory[] SPAWNING_CATEGORIES = (MobCategory[]) Stream.of(MobCategory.values()).filter((mobcategory) -> { +- return mobcategory != MobCategory.MISC; ++ private static final MobCategory[] SPAWNING_CATEGORIES = (MobCategory[]) Stream.of(MobCategory.values()).filter((enumcreaturetype) -> { ++ return enumcreaturetype != MobCategory.MISC; + }).toArray((i) -> { + return new MobCategory[i]; + }); + + private NaturalSpawner() {} + +- public static NaturalSpawner.SpawnState createState(int i, Iterable<Entity> iterable, NaturalSpawner.ChunkGetter naturalspawner_chunkgetter, LocalMobCapCalculator localmobcapcalculator) { +- PotentialCalculator potentialcalculator = new PotentialCalculator(); ++ public static NaturalSpawner.SpawnState createState(int spawnableChunkCount, Iterable<Entity> entities, NaturalSpawner.ChunkGetter chunkGetter, LocalMobCapCalculator calculator) { ++ PotentialCalculator spawnercreatureprobabilities = new PotentialCalculator(); + Object2IntOpenHashMap<MobCategory> object2intopenhashmap = new Object2IntOpenHashMap(); +- Iterator iterator = iterable.iterator(); ++ Iterator iterator = entities.iterator(); + + while (iterator.hasNext()) { + Entity entity = (Entity) iterator.next(); + + if (entity instanceof Mob) { +- Mob mob = (Mob) entity; ++ Mob entityinsentient = (Mob) entity; + +- if (mob.isPersistenceRequired() || mob.requiresCustomPersistence()) { ++ if (entityinsentient.isPersistenceRequired() || entityinsentient.requiresCustomPersistence()) { + continue; + } + } + +- MobCategory mobcategory = entity.getType().getCategory(); ++ MobCategory enumcreaturetype = entity.getType().getCategory(); + +- if (mobcategory != MobCategory.MISC) { +- BlockPos blockpos = entity.blockPosition(); ++ if (enumcreaturetype != MobCategory.MISC) { ++ BlockPos blockposition = entity.blockPosition(); + +- naturalspawner_chunkgetter.query(ChunkPos.asLong(blockpos), (levelchunk) -> { +- MobSpawnSettings.MobSpawnCost mobspawnsettings_mobspawncost = getRoughBiome(blockpos, levelchunk).getMobSettings().getMobSpawnCost(entity.getType()); ++ chunkGetter.query(ChunkPos.asLong(blockposition), (chunk) -> { ++ MobSpawnSettings.MobSpawnCost biomesettingsmobs_b = getRoughBiome(blockposition, chunk).getMobSettings().getMobSpawnCost(entity.getType()); + +- if (mobspawnsettings_mobspawncost != null) { +- potentialcalculator.addCharge(entity.blockPosition(), mobspawnsettings_mobspawncost.charge()); ++ if (biomesettingsmobs_b != null) { ++ spawnercreatureprobabilities.addCharge(entity.blockPosition(), biomesettingsmobs_b.charge()); + } + + if (entity instanceof Mob) { +- localmobcapcalculator.addMob(levelchunk.getPos(), mobcategory); ++ calculator.addMob(chunk.getPos(), enumcreaturetype); + } + +- object2intopenhashmap.addTo(mobcategory, 1); ++ object2intopenhashmap.addTo(enumcreaturetype, 1); + }); + } + } + +- return new NaturalSpawner.SpawnState(i, object2intopenhashmap, potentialcalculator, localmobcapcalculator); ++ return new NaturalSpawner.SpawnState(spawnableChunkCount, object2intopenhashmap, spawnercreatureprobabilities, calculator); + } + +- static Biome getRoughBiome(BlockPos blockpos, ChunkAccess chunkaccess) { +- return (Biome) chunkaccess.getNoiseBiome(QuartPos.fromBlock(blockpos.getX()), QuartPos.fromBlock(blockpos.getY()), QuartPos.fromBlock(blockpos.getZ())).value(); ++ static Biome getRoughBiome(BlockPos pos, ChunkAccess chunk) { ++ return (Biome) chunk.getNoiseBiome(QuartPos.fromBlock(pos.getX()), QuartPos.fromBlock(pos.getY()), QuartPos.fromBlock(pos.getZ())).value(); + } + +- public static void spawnForChunk(ServerLevel serverlevel, LevelChunk levelchunk, NaturalSpawner.SpawnState naturalspawner_spawnstate, boolean flag, boolean flag1, boolean flag2) { +- serverlevel.getProfiler().push("spawner"); +- MobCategory[] amobcategory = NaturalSpawner.SPAWNING_CATEGORIES; +- int i = amobcategory.length; ++ public static void spawnForChunk(ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnState spawnState, boolean spawnFriendlies, boolean spawnMonsters, boolean forcedDespawn) { ++ level.getProfiler().push("spawner"); ++ MobCategory[] aenumcreaturetype = NaturalSpawner.SPAWNING_CATEGORIES; ++ int i = aenumcreaturetype.length; + ++ LevelData worlddata = level.getLevelData(); // CraftBukkit - Other mob type spawn tick rate ++ + for (int j = 0; j < i; ++j) { +- MobCategory mobcategory = amobcategory[j]; ++ MobCategory enumcreaturetype = aenumcreaturetype[j]; ++ // CraftBukkit start - Use per-world spawn limits ++ boolean spawnThisTick = true; ++ int limit = enumcreaturetype.getMaxInstancesPerChunk(); ++ SpawnCategory spawnCategory = CraftSpawnCategory.toBukkit(enumcreaturetype); ++ if (CraftSpawnCategory.isValidForLimits(spawnCategory)) { ++ spawnThisTick = level.ticksPerSpawnCategory.getLong(spawnCategory) != 0 && worlddata.getGameTime() % level.ticksPerSpawnCategory.getLong(spawnCategory) == 0; ++ limit = level.getWorld().getSpawnLimit(spawnCategory); ++ } + +- if ((flag || !mobcategory.isFriendly()) && (flag1 || mobcategory.isFriendly()) && (flag2 || !mobcategory.isPersistent()) && naturalspawner_spawnstate.canSpawnForCategory(mobcategory, levelchunk.getPos())) { +- Objects.requireNonNull(naturalspawner_spawnstate); +- NaturalSpawner.SpawnPredicate naturalspawner_spawnpredicate = naturalspawner_spawnstate::canSpawn; ++ if (!spawnThisTick || limit == 0) { ++ continue; ++ } + +- Objects.requireNonNull(naturalspawner_spawnstate); +- spawnCategoryForChunk(mobcategory, serverlevel, levelchunk, naturalspawner_spawnpredicate, naturalspawner_spawnstate::afterSpawn); ++ if ((spawnFriendlies || !enumcreaturetype.isFriendly()) && (spawnMonsters || enumcreaturetype.isFriendly()) && (forcedDespawn || !enumcreaturetype.isPersistent()) && spawnState.canSpawnForCategory(enumcreaturetype, chunk.getPos(), limit)) { ++ // CraftBukkit end ++ Objects.requireNonNull(spawnState); ++ NaturalSpawner.SpawnPredicate spawnercreature_c = spawnState::canSpawn; ++ ++ Objects.requireNonNull(spawnState); ++ spawnCategoryForChunk(enumcreaturetype, level, chunk, spawnercreature_c, spawnState::afterSpawn); + } + } + +- serverlevel.getProfiler().pop(); ++ level.getProfiler().pop(); + } + +- public static void spawnCategoryForChunk(MobCategory mobcategory, ServerLevel serverlevel, LevelChunk levelchunk, NaturalSpawner.SpawnPredicate naturalspawner_spawnpredicate, NaturalSpawner.AfterSpawnCallback naturalspawner_afterspawncallback) { +- BlockPos blockpos = getRandomPosWithin(serverlevel, levelchunk); ++ public static void spawnCategoryForChunk(MobCategory category, ServerLevel level, LevelChunk chunk, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback) { ++ BlockPos blockposition = getRandomPosWithin(level, chunk); + +- if (blockpos.getY() >= serverlevel.getMinBuildHeight() + 1) { +- spawnCategoryForPosition(mobcategory, serverlevel, levelchunk, blockpos, naturalspawner_spawnpredicate, naturalspawner_afterspawncallback); ++ if (blockposition.getY() >= level.getMinBuildHeight() + 1) { ++ spawnCategoryForPosition(category, level, chunk, blockposition, filter, callback); + } + } + + @VisibleForDebug +- public static void spawnCategoryForPosition(MobCategory mobcategory, ServerLevel serverlevel, BlockPos blockpos) { +- spawnCategoryForPosition(mobcategory, serverlevel, serverlevel.getChunk(blockpos), blockpos, (entitytype, blockpos1, chunkaccess) -> { ++ public static void spawnCategoryForPosition(MobCategory category, ServerLevel level, BlockPos pos) { ++ spawnCategoryForPosition(category, level, level.getChunk(pos), pos, (entitytypes, blockposition1, ichunkaccess) -> { + return true; +- }, (mob, chunkaccess) -> { ++ }, (entityinsentient, ichunkaccess) -> { + }); + } + +- public static void spawnCategoryForPosition(MobCategory mobcategory, ServerLevel serverlevel, ChunkAccess chunkaccess, BlockPos blockpos, NaturalSpawner.SpawnPredicate naturalspawner_spawnpredicate, NaturalSpawner.AfterSpawnCallback naturalspawner_afterspawncallback) { +- StructureManager structuremanager = serverlevel.structureManager(); +- ChunkGenerator chunkgenerator = serverlevel.getChunkSource().getGenerator(); +- int i = blockpos.getY(); +- BlockState blockstate = chunkaccess.getBlockState(blockpos); ++ public static void spawnCategoryForPosition(MobCategory category, ServerLevel level, ChunkAccess chunk, BlockPos pos, NaturalSpawner.SpawnPredicate filter, NaturalSpawner.AfterSpawnCallback callback) { ++ StructureManager structuremanager = level.structureManager(); ++ ChunkGenerator chunkgenerator = level.getChunkSource().getGenerator(); ++ int i = pos.getY(); ++ IBlockData iblockdata = chunk.getBlockState(pos); + +- if (!blockstate.isRedstoneConductor(chunkaccess, blockpos)) { +- BlockPos.MutableBlockPos blockpos_mutableblockpos = new BlockPos.MutableBlockPos(); ++ if (!iblockdata.isRedstoneConductor(chunk, pos)) { ++ BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(); + int j = 0; + int k = 0; + + while (k < 3) { +- int l = blockpos.getX(); +- int i1 = blockpos.getZ(); ++ int l = pos.getX(); ++ int i1 = pos.getZ(); + boolean flag = true; +- MobSpawnSettings.SpawnerData mobspawnsettings_spawnerdata = null; +- SpawnGroupData spawngroupdata = null; +- int j1 = Mth.ceil(serverlevel.random.nextFloat() * 4.0F); ++ MobSpawnSettings.SpawnerData biomesettingsmobs_c = null; ++ GroupDataEntity groupdataentity = null; ++ int j1 = Mth.ceil(level.random.nextFloat() * 4.0F); + int k1 = 0; + int l1 = 0; + +@@ -169,47 +189,52 @@ + if (l1 < j1) { + label53: + { +- l += serverlevel.random.nextInt(6) - serverlevel.random.nextInt(6); +- i1 += serverlevel.random.nextInt(6) - serverlevel.random.nextInt(6); +- blockpos_mutableblockpos.set(l, i, i1); ++ l += level.random.nextInt(6) - level.random.nextInt(6); ++ i1 += level.random.nextInt(6) - level.random.nextInt(6); ++ blockposition_mutableblockposition.set(l, i, i1); + double d0 = (double) l + 0.5D; + double d1 = (double) i1 + 0.5D; +- Player player = serverlevel.getNearestPlayer(d0, (double) i, d1, -1.0D, false); ++ Player entityhuman = level.getNearestPlayer(d0, (double) i, d1, -1.0D, false); + +- if (player != null) { +- double d2 = player.distanceToSqr(d0, (double) i, d1); ++ if (entityhuman != null) { ++ double d2 = entityhuman.distanceToSqr(d0, (double) i, d1); + +- if (isRightDistanceToPlayerAndSpawnPoint(serverlevel, chunkaccess, blockpos_mutableblockpos, d2)) { +- if (mobspawnsettings_spawnerdata == null) { +- Optional<MobSpawnSettings.SpawnerData> optional = getRandomSpawnMobAt(serverlevel, structuremanager, chunkgenerator, mobcategory, serverlevel.random, blockpos_mutableblockpos); ++ if (isRightDistanceToPlayerAndSpawnPoint(level, chunk, blockposition_mutableblockposition, d2)) { ++ if (biomesettingsmobs_c == null) { ++ Optional<MobSpawnSettings.SpawnerData> optional = getRandomSpawnMobAt(level, structuremanager, chunkgenerator, category, level.random, blockposition_mutableblockposition); + + if (optional.isEmpty()) { + break label53; + } + +- mobspawnsettings_spawnerdata = (MobSpawnSettings.SpawnerData) optional.get(); +- j1 = mobspawnsettings_spawnerdata.minCount + serverlevel.random.nextInt(1 + mobspawnsettings_spawnerdata.maxCount - mobspawnsettings_spawnerdata.minCount); ++ biomesettingsmobs_c = (MobSpawnSettings.SpawnerData) optional.get(); ++ j1 = biomesettingsmobs_c.minCount + level.random.nextInt(1 + biomesettingsmobs_c.maxCount - biomesettingsmobs_c.minCount); + } + +- if (isValidSpawnPostitionForType(serverlevel, mobcategory, structuremanager, chunkgenerator, mobspawnsettings_spawnerdata, blockpos_mutableblockpos, d2) && naturalspawner_spawnpredicate.test(mobspawnsettings_spawnerdata.type, blockpos_mutableblockpos, chunkaccess)) { +- Mob mob = getMobForSpawn(serverlevel, mobspawnsettings_spawnerdata.type); ++ if (isValidSpawnPostitionForType(level, category, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2) && filter.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) { ++ Mob entityinsentient = getMobForSpawn(level, biomesettingsmobs_c.type); + +- if (mob == null) { ++ if (entityinsentient == null) { + return; + } + +- mob.moveTo(d0, (double) i, d1, serverlevel.random.nextFloat() * 360.0F, 0.0F); +- if (isValidPositionForMob(serverlevel, mob, d2)) { +- spawngroupdata = mob.finalizeSpawn(serverlevel, serverlevel.getCurrentDifficultyAt(mob.blockPosition()), MobSpawnType.NATURAL, spawngroupdata, (CompoundTag) null); +- ++j; +- ++k1; +- serverlevel.addFreshEntityWithPassengers(mob); +- naturalspawner_afterspawncallback.run(mob, chunkaccess); +- if (j >= mob.getMaxSpawnClusterSize()) { ++ entityinsentient.moveTo(d0, (double) i, d1, level.random.nextFloat() * 360.0F, 0.0F); ++ if (isValidPositionForMob(level, entityinsentient, d2)) { ++ groupdataentity = entityinsentient.finalizeSpawn(level, level.getCurrentDifficultyAt(entityinsentient.blockPosition()), EnumMobSpawn.NATURAL, groupdataentity, (CompoundTag) null); ++ // CraftBukkit start ++ // SPIGOT-7045: Give ocelot babies back their special spawn reason. Note: This is the only modification required as ocelots count as monsters which means they only spawn during normal chunk ticking and do not spawn during chunk generation as starter mobs. ++ level.addFreshEntityWithPassengers(entityinsentient, (entityinsentient instanceof net.minecraft.world.entity.animal.Ocelot && !((org.bukkit.entity.Ageable) entityinsentient.getBukkitEntity()).isAdult()) ? SpawnReason.OCELOT_BABY : SpawnReason.NATURAL); ++ if (!entityinsentient.isRemoved()) { ++ ++j; ++ ++k1; ++ callback.run(entityinsentient, chunk); ++ } ++ // CraftBukkit end ++ if (j >= entityinsentient.getMaxSpawnClusterSize()) { + return; + } + +- if (mob.isMaxGroupSizeReached(k1)) { ++ if (entityinsentient.isMaxGroupSizeReached(k1)) { + break label53; + } + } +@@ -230,38 +255,38 @@ + } + } + +- private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel serverlevel, ChunkAccess chunkaccess, BlockPos.MutableBlockPos blockpos_mutableblockpos, double d0) { +- return d0 <= 576.0D ? false : (serverlevel.getSharedSpawnPos().closerToCenterThan(new Vec3((double) blockpos_mutableblockpos.getX() + 0.5D, (double) blockpos_mutableblockpos.getY(), (double) blockpos_mutableblockpos.getZ() + 0.5D), 24.0D) ? false : Objects.equals(new ChunkPos(blockpos_mutableblockpos), chunkaccess.getPos()) || serverlevel.isNaturalSpawningAllowed((BlockPos) blockpos_mutableblockpos)); ++ private static boolean isRightDistanceToPlayerAndSpawnPoint(ServerLevel level, ChunkAccess chunk, BlockPos.MutableBlockPos pos, double distance) { ++ return distance <= 576.0D ? false : (level.getSharedSpawnPos().closerToCenterThan(new Vec3((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D), 24.0D) ? false : Objects.equals(new ChunkPos(pos), chunk.getPos()) || level.isNaturalSpawningAllowed((BlockPos) pos)); + } + +- private static boolean isValidSpawnPostitionForType(ServerLevel serverlevel, MobCategory mobcategory, StructureManager structuremanager, ChunkGenerator chunkgenerator, MobSpawnSettings.SpawnerData mobspawnsettings_spawnerdata, BlockPos.MutableBlockPos blockpos_mutableblockpos, double d0) { +- EntityType<?> entitytype = mobspawnsettings_spawnerdata.type; ++ private static boolean isValidSpawnPostitionForType(ServerLevel level, MobCategory category, StructureManager structureManager, ChunkGenerator generator, MobSpawnSettings.SpawnerData data, BlockPos.MutableBlockPos pos, double distance) { ++ EntityType<?> entitytypes = data.type; + +- if (entitytype.getCategory() == MobCategory.MISC) { ++ if (entitytypes.getCategory() == MobCategory.MISC) { + return false; +- } else if (!entitytype.canSpawnFarFromPlayer() && d0 > (double) (entitytype.getCategory().getDespawnDistance() * entitytype.getCategory().getDespawnDistance())) { ++ } else if (!entitytypes.canSpawnFarFromPlayer() && distance > (double) (entitytypes.getCategory().getDespawnDistance() * entitytypes.getCategory().getDespawnDistance())) { + return false; +- } else if (entitytype.canSummon() && canSpawnMobAt(serverlevel, structuremanager, chunkgenerator, mobcategory, mobspawnsettings_spawnerdata, blockpos_mutableblockpos)) { +- SpawnPlacements.Type spawnplacements_type = SpawnPlacements.getPlacementType(entitytype); ++ } else if (entitytypes.canSummon() && canSpawnMobAt(level, structureManager, generator, category, data, pos)) { ++ SpawnPlacements.Surface entitypositiontypes_surface = SpawnPlacements.getPlacementType(entitytypes); + +- return !isSpawnPositionOk(spawnplacements_type, serverlevel, blockpos_mutableblockpos, entitytype) ? false : (!SpawnPlacements.checkSpawnRules(entitytype, serverlevel, MobSpawnType.NATURAL, blockpos_mutableblockpos, serverlevel.random) ? false : serverlevel.noCollision(entitytype.getAABB((double) blockpos_mutableblockpos.getX() + 0.5D, (double) blockpos_mutableblockpos.getY(), (double) blockpos_mutableblockpos.getZ() + 0.5D))); ++ return !isSpawnPositionOk(entitypositiontypes_surface, level, pos, entitytypes) ? false : (!SpawnPlacements.checkSpawnRules(entitytypes, level, EnumMobSpawn.NATURAL, pos, level.random) ? false : level.noCollision(entitytypes.getAABB((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D))); + } else { + return false; + } + } + + @Nullable +- private static Mob getMobForSpawn(ServerLevel serverlevel, EntityType<?> entitytype) { ++ private static Mob getMobForSpawn(ServerLevel level, EntityType<?> entityType) { + try { +- Entity entity = entitytype.create(serverlevel); ++ Entity entity = entityType.create(level); + + if (entity instanceof Mob) { +- Mob mob = (Mob) entity; ++ Mob entityinsentient = (Mob) entity; + +- return mob; ++ return entityinsentient; + } + +- NaturalSpawner.LOGGER.warn("Can't spawn entity of type: {}", BuiltInRegistries.ENTITY_TYPE.getKey(entitytype)); ++ NaturalSpawner.LOGGER.warn("Can't spawn entity of type: {}", BuiltInRegistries.ENTITY_TYPE.getKey(entityType)); + } catch (Exception exception) { + NaturalSpawner.LOGGER.warn("Failed to create mob", exception); + } +@@ -269,90 +294,90 @@ + return null; + } + +- private static boolean isValidPositionForMob(ServerLevel serverlevel, Mob mob, double d0) { +- return d0 > (double) (mob.getType().getCategory().getDespawnDistance() * mob.getType().getCategory().getDespawnDistance()) && mob.removeWhenFarAway(d0) ? false : mob.checkSpawnRules(serverlevel, MobSpawnType.NATURAL) && mob.checkSpawnObstruction(serverlevel); ++ private static boolean isValidPositionForMob(ServerLevel level, Mob mob, double distance) { ++ return distance > (double) (mob.getType().getCategory().getDespawnDistance() * mob.getType().getCategory().getDespawnDistance()) && mob.removeWhenFarAway(distance) ? false : mob.checkSpawnRules(level, EnumMobSpawn.NATURAL) && mob.checkSpawnObstruction(level); + } + +- private static Optional<MobSpawnSettings.SpawnerData> getRandomSpawnMobAt(ServerLevel serverlevel, StructureManager structuremanager, ChunkGenerator chunkgenerator, MobCategory mobcategory, RandomSource randomsource, BlockPos blockpos) { +- Holder<Biome> holder = serverlevel.getBiome(blockpos); ++ private static Optional<MobSpawnSettings.SpawnerData> getRandomSpawnMobAt(ServerLevel level, StructureManager structureManager, ChunkGenerator generator, MobCategory category, RandomSource random, BlockPos pos) { ++ Holder<Biome> holder = level.getBiome(pos); + +- return mobcategory == MobCategory.WATER_AMBIENT && holder.is(BiomeTags.REDUCED_WATER_AMBIENT_SPAWNS) && randomsource.nextFloat() < 0.98F ? Optional.empty() : mobsAt(serverlevel, structuremanager, chunkgenerator, mobcategory, blockpos, holder).getRandom(randomsource); ++ return category == MobCategory.WATER_AMBIENT && holder.is(BiomeTags.REDUCED_WATER_AMBIENT_SPAWNS) && random.nextFloat() < 0.98F ? Optional.empty() : mobsAt(level, structureManager, generator, category, pos, holder).getRandom(random); + } + +- private static boolean canSpawnMobAt(ServerLevel serverlevel, StructureManager structuremanager, ChunkGenerator chunkgenerator, MobCategory mobcategory, MobSpawnSettings.SpawnerData mobspawnsettings_spawnerdata, BlockPos blockpos) { +- return mobsAt(serverlevel, structuremanager, chunkgenerator, mobcategory, blockpos, (Holder) null).unwrap().contains(mobspawnsettings_spawnerdata); ++ private static boolean canSpawnMobAt(ServerLevel level, StructureManager structureManager, ChunkGenerator generator, MobCategory category, MobSpawnSettings.SpawnerData data, BlockPos pos) { ++ return mobsAt(level, structureManager, generator, category, pos, (Holder) null).unwrap().contains(data); + } + +- private static WeightedRandomList<MobSpawnSettings.SpawnerData> mobsAt(ServerLevel serverlevel, StructureManager structuremanager, ChunkGenerator chunkgenerator, MobCategory mobcategory, BlockPos blockpos, @Nullable Holder<Biome> holder) { +- return isInNetherFortressBounds(blockpos, serverlevel, mobcategory, structuremanager) ? NetherFortressStructure.FORTRESS_ENEMIES : chunkgenerator.getMobsAt(holder != null ? holder : serverlevel.getBiome(blockpos), structuremanager, mobcategory, blockpos); ++ private static WeightedRandomList<MobSpawnSettings.SpawnerData> mobsAt(ServerLevel level, StructureManager structureManager, ChunkGenerator generator, MobCategory category, BlockPos pos, @Nullable Holder<Biome> biome) { ++ return isInNetherFortressBounds(pos, level, category, structureManager) ? NetherFortressStructure.FORTRESS_ENEMIES : generator.getMobsAt(biome != null ? biome : level.getBiome(pos), structureManager, category, pos); + } + +- public static boolean isInNetherFortressBounds(BlockPos blockpos, ServerLevel serverlevel, MobCategory mobcategory, StructureManager structuremanager) { +- if (mobcategory == MobCategory.MONSTER && serverlevel.getBlockState(blockpos.below()).is(Blocks.NETHER_BRICKS)) { +- Structure structure = (Structure) structuremanager.registryAccess().registryOrThrow(Registries.STRUCTURE).get(BuiltinStructures.FORTRESS); ++ 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 = (Structure) structureManager.registryAccess().registryOrThrow(Registries.STRUCTURE).get(BuiltinStructures.FORTRESS); + +- return structure == null ? false : structuremanager.getStructureAt(blockpos, structure).isValid(); ++ return structure == null ? false : structureManager.getStructureAt(pos, structure).isValid(); + } else { + return false; + } + } + +- private static BlockPos getRandomPosWithin(Level level, LevelChunk levelchunk) { +- ChunkPos chunkpos = levelchunk.getPos(); +- int i = chunkpos.getMinBlockX() + level.random.nextInt(16); +- int j = chunkpos.getMinBlockZ() + level.random.nextInt(16); +- int k = levelchunk.getHeight(Heightmap.Types.WORLD_SURFACE, i, j) + 1; ++ private static BlockPos getRandomPosWithin(Level level, LevelChunk chunk) { ++ ChunkPos chunkcoordintpair = chunk.getPos(); ++ int i = chunkcoordintpair.getMinBlockX() + level.random.nextInt(16); ++ int j = chunkcoordintpair.getMinBlockZ() + level.random.nextInt(16); ++ int k = chunk.getHeight(Heightmap.Types.WORLD_SURFACE, i, j) + 1; + int l = Mth.randomBetweenInclusive(level.random, level.getMinBuildHeight(), k); + + return new BlockPos(i, l, j); + } + +- public static boolean isValidEmptySpawnBlock(BlockGetter blockgetter, BlockPos blockpos, BlockState blockstate, FluidState fluidstate, EntityType<?> entitytype) { +- return blockstate.isCollisionShapeFullBlock(blockgetter, blockpos) ? false : (blockstate.isSignalSource() ? false : (!fluidstate.isEmpty() ? false : (blockstate.is(BlockTags.PREVENT_MOB_SPAWNING_INSIDE) ? false : !entitytype.isBlockDangerous(blockstate)))); ++ public static boolean isValidEmptySpawnBlock(BlockGetter block, BlockPos pos, IBlockData blockState, FluidState fluidState, EntityType<?> entityType) { ++ return blockState.isCollisionShapeFullBlock(block, pos) ? false : (blockState.isSignalSource() ? false : (!fluidState.isEmpty() ? false : (blockState.is(BlockTags.PREVENT_MOB_SPAWNING_INSIDE) ? false : !entityType.isBlockDangerous(blockState)))); + } + +- public static boolean isSpawnPositionOk(SpawnPlacements.Type spawnplacements_type, LevelReader levelreader, BlockPos blockpos, @Nullable EntityType<?> entitytype) { +- if (spawnplacements_type == SpawnPlacements.Type.NO_RESTRICTIONS) { ++ public static boolean isSpawnPositionOk(SpawnPlacements.Surface placeType, LevelReader level, BlockPos pos, @Nullable EntityType<?> entityType) { ++ if (placeType == SpawnPlacements.Surface.NO_RESTRICTIONS) { + return true; +- } else if (entitytype != null && levelreader.getWorldBorder().isWithinBounds(blockpos)) { +- BlockState blockstate = levelreader.getBlockState(blockpos); +- FluidState fluidstate = levelreader.getFluidState(blockpos); +- BlockPos blockpos1 = blockpos.above(); +- BlockPos blockpos2 = blockpos.below(); ++ } else if (entityType != null && level.getWorldBorder().isWithinBounds(pos)) { ++ IBlockData iblockdata = level.getBlockState(pos); ++ FluidState fluid = level.getFluidState(pos); ++ BlockPos blockposition1 = pos.above(); ++ BlockPos blockposition2 = pos.below(); + +- switch (spawnplacements_type) { ++ switch (placeType) { + case IN_WATER: +- return fluidstate.is(FluidTags.WATER) && !levelreader.getBlockState(blockpos1).isRedstoneConductor(levelreader, blockpos1); ++ return fluid.is(FluidTags.WATER) && !level.getBlockState(blockposition1).isRedstoneConductor(level, blockposition1); + case IN_LAVA: +- return fluidstate.is(FluidTags.LAVA); ++ return fluid.is(FluidTags.LAVA); + case ON_GROUND: + default: +- BlockState blockstate1 = levelreader.getBlockState(blockpos2); ++ IBlockData iblockdata1 = level.getBlockState(blockposition2); + +- return !blockstate1.isValidSpawn(levelreader, blockpos2, entitytype) ? false : isValidEmptySpawnBlock(levelreader, blockpos, blockstate, fluidstate, entitytype) && isValidEmptySpawnBlock(levelreader, blockpos1, levelreader.getBlockState(blockpos1), levelreader.getFluidState(blockpos1), entitytype); ++ return !iblockdata1.isValidSpawn(level, blockposition2, entityType) ? false : isValidEmptySpawnBlock(level, pos, iblockdata, fluid, entityType) && isValidEmptySpawnBlock(level, blockposition1, level.getBlockState(blockposition1), level.getFluidState(blockposition1), entityType); + } + } else { + return false; + } + } + +- public static void spawnMobsForChunkGeneration(ServerLevelAccessor serverlevelaccessor, Holder<Biome> holder, ChunkPos chunkpos, RandomSource randomsource) { +- MobSpawnSettings mobspawnsettings = ((Biome) holder.value()).getMobSettings(); +- WeightedRandomList<MobSpawnSettings.SpawnerData> weightedrandomlist = mobspawnsettings.getMobs(MobCategory.CREATURE); ++ public static void spawnMobsForChunkGeneration(ServerLevelAccessor levelAccessor, Holder<Biome> biome, ChunkPos chunkPos, RandomSource random) { ++ MobSpawnSettings biomesettingsmobs = ((Biome) biome.value()).getMobSettings(); ++ WeightedRandomList<MobSpawnSettings.SpawnerData> weightedrandomlist = biomesettingsmobs.getMobs(MobCategory.CREATURE); + + if (!weightedrandomlist.isEmpty()) { +- int i = chunkpos.getMinBlockX(); +- int j = chunkpos.getMinBlockZ(); ++ int i = chunkPos.getMinBlockX(); ++ int j = chunkPos.getMinBlockZ(); + +- while (randomsource.nextFloat() < mobspawnsettings.getCreatureProbability()) { +- Optional<MobSpawnSettings.SpawnerData> optional = weightedrandomlist.getRandom(randomsource); ++ while (random.nextFloat() < biomesettingsmobs.getCreatureProbability()) { ++ Optional<MobSpawnSettings.SpawnerData> optional = weightedrandomlist.getRandom(random); + + if (!optional.isEmpty()) { +- MobSpawnSettings.SpawnerData mobspawnsettings_spawnerdata = (MobSpawnSettings.SpawnerData) optional.get(); +- int k = mobspawnsettings_spawnerdata.minCount + randomsource.nextInt(1 + mobspawnsettings_spawnerdata.maxCount - mobspawnsettings_spawnerdata.minCount); +- SpawnGroupData spawngroupdata = null; +- int l = i + randomsource.nextInt(16); +- int i1 = j + randomsource.nextInt(16); ++ MobSpawnSettings.SpawnerData biomesettingsmobs_c = (MobSpawnSettings.SpawnerData) optional.get(); ++ int k = biomesettingsmobs_c.minCount + random.nextInt(1 + biomesettingsmobs_c.maxCount - biomesettingsmobs_c.minCount); ++ GroupDataEntity groupdataentity = null; ++ int l = i + random.nextInt(16); ++ int i1 = j + random.nextInt(16); + int j1 = l; + int k1 = i1; + +@@ -360,21 +385,21 @@ + boolean flag = false; + + for (int i2 = 0; !flag && i2 < 4; ++i2) { +- BlockPos blockpos = getTopNonCollidingPos(serverlevelaccessor, mobspawnsettings_spawnerdata.type, l, i1); ++ BlockPos blockposition = getTopNonCollidingPos(levelAccessor, biomesettingsmobs_c.type, l, i1); + +- if (mobspawnsettings_spawnerdata.type.canSummon() && isSpawnPositionOk(SpawnPlacements.getPlacementType(mobspawnsettings_spawnerdata.type), serverlevelaccessor, blockpos, mobspawnsettings_spawnerdata.type)) { +- float f = mobspawnsettings_spawnerdata.type.getWidth(); ++ if (biomesettingsmobs_c.type.canSummon() && isSpawnPositionOk(SpawnPlacements.getPlacementType(biomesettingsmobs_c.type), levelAccessor, blockposition, biomesettingsmobs_c.type)) { ++ float f = biomesettingsmobs_c.type.getWidth(); + double d0 = Mth.clamp((double) l, (double) i + (double) f, (double) i + 16.0D - (double) f); + double d1 = Mth.clamp((double) i1, (double) j + (double) f, (double) j + 16.0D - (double) f); + +- if (!serverlevelaccessor.noCollision(mobspawnsettings_spawnerdata.type.getAABB(d0, (double) blockpos.getY(), d1)) || !SpawnPlacements.checkSpawnRules(mobspawnsettings_spawnerdata.type, serverlevelaccessor, MobSpawnType.CHUNK_GENERATION, BlockPos.containing(d0, (double) blockpos.getY(), d1), serverlevelaccessor.getRandom())) { ++ if (!levelAccessor.noCollision(biomesettingsmobs_c.type.getAABB(d0, (double) blockposition.getY(), d1)) || !SpawnPlacements.checkSpawnRules(biomesettingsmobs_c.type, levelAccessor, EnumMobSpawn.CHUNK_GENERATION, BlockPos.containing(d0, (double) blockposition.getY(), d1), levelAccessor.getRandom())) { + continue; + } + + Entity entity; + + try { +- entity = mobspawnsettings_spawnerdata.type.create(serverlevelaccessor.getLevel()); ++ entity = biomesettingsmobs_c.type.create(levelAccessor.getLevel()); + } catch (Exception exception) { + NaturalSpawner.LOGGER.warn("Failed to create mob", exception); + continue; +@@ -384,22 +409,22 @@ + continue; + } + +- entity.moveTo(d0, (double) blockpos.getY(), d1, randomsource.nextFloat() * 360.0F, 0.0F); ++ entity.moveTo(d0, (double) blockposition.getY(), d1, random.nextFloat() * 360.0F, 0.0F); + if (entity instanceof Mob) { +- Mob mob = (Mob) entity; ++ Mob entityinsentient = (Mob) entity; + +- if (mob.checkSpawnRules(serverlevelaccessor, MobSpawnType.CHUNK_GENERATION) && mob.checkSpawnObstruction(serverlevelaccessor)) { +- spawngroupdata = mob.finalizeSpawn(serverlevelaccessor, serverlevelaccessor.getCurrentDifficultyAt(mob.blockPosition()), MobSpawnType.CHUNK_GENERATION, spawngroupdata, (CompoundTag) null); +- serverlevelaccessor.addFreshEntityWithPassengers(mob); ++ if (entityinsentient.checkSpawnRules(levelAccessor, EnumMobSpawn.CHUNK_GENERATION) && entityinsentient.checkSpawnObstruction(levelAccessor)) { ++ groupdataentity = entityinsentient.finalizeSpawn(levelAccessor, levelAccessor.getCurrentDifficultyAt(entityinsentient.blockPosition()), EnumMobSpawn.CHUNK_GENERATION, groupdataentity, (CompoundTag) null); ++ levelAccessor.addFreshEntityWithPassengers(entityinsentient, SpawnReason.CHUNK_GEN); // CraftBukkit + flag = true; + } + } + } + +- l += randomsource.nextInt(5) - randomsource.nextInt(5); ++ l += random.nextInt(5) - random.nextInt(5); + +- for (i1 += randomsource.nextInt(5) - randomsource.nextInt(5); l < i || l >= i + 16 || i1 < j || i1 >= j + 16; i1 = k1 + randomsource.nextInt(5) - randomsource.nextInt(5)) { +- l = j1 + randomsource.nextInt(5) - randomsource.nextInt(5); ++ for (i1 += random.nextInt(5) - random.nextInt(5); l < i || l >= i + 16 || i1 < j || i1 >= j + 16; i1 = k1 + random.nextInt(5) - random.nextInt(5)) { ++ l = j1 + random.nextInt(5) - random.nextInt(5); + } + } + } +@@ -409,29 +434,29 @@ + } + } + +- private static BlockPos getTopNonCollidingPos(LevelReader levelreader, EntityType<?> entitytype, int i, int j) { +- int k = levelreader.getHeight(SpawnPlacements.getHeightmapType(entitytype), i, j); +- BlockPos.MutableBlockPos blockpos_mutableblockpos = new BlockPos.MutableBlockPos(i, k, j); ++ private static BlockPos getTopNonCollidingPos(LevelReader level, EntityType<?> entityType, int x, int z) { ++ int k = level.getHeight(SpawnPlacements.getHeightmapType(entityType), x, z); ++ BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos(x, k, z); + +- if (levelreader.dimensionType().hasCeiling()) { ++ if (level.dimensionType().hasCeiling()) { + do { +- blockpos_mutableblockpos.move(Direction.DOWN); +- } while (!levelreader.getBlockState(blockpos_mutableblockpos).isAir()); ++ blockposition_mutableblockposition.move(Direction.DOWN); ++ } while (!level.getBlockState(blockposition_mutableblockposition).isAir()); + + do { +- blockpos_mutableblockpos.move(Direction.DOWN); +- } while (levelreader.getBlockState(blockpos_mutableblockpos).isAir() && blockpos_mutableblockpos.getY() > levelreader.getMinBuildHeight()); ++ blockposition_mutableblockposition.move(Direction.DOWN); ++ } while (level.getBlockState(blockposition_mutableblockposition).isAir() && blockposition_mutableblockposition.getY() > level.getMinBuildHeight()); + } + +- if (SpawnPlacements.getPlacementType(entitytype) == SpawnPlacements.Type.ON_GROUND) { +- BlockPos blockpos = blockpos_mutableblockpos.below(); ++ if (SpawnPlacements.getPlacementType(entityType) == SpawnPlacements.Surface.ON_GROUND) { ++ BlockPos blockposition = blockposition_mutableblockposition.below(); + +- if (levelreader.getBlockState(blockpos).isPathfindable(levelreader, blockpos, PathComputationType.LAND)) { +- return blockpos; ++ if (level.getBlockState(blockposition).isPathfindable(level, blockposition, PathMode.LAND)) { ++ return blockposition; + } + } + +- return blockpos_mutableblockpos.immutable(); ++ return blockposition_mutableblockposition.immutable(); + } + + @FunctionalInterface +@@ -453,54 +478,54 @@ + private EntityType<?> lastCheckedType; + private double lastCharge; + +- SpawnState(int i, Object2IntOpenHashMap<MobCategory> object2intopenhashmap, PotentialCalculator potentialcalculator, LocalMobCapCalculator localmobcapcalculator) { +- this.spawnableChunkCount = i; +- this.mobCategoryCounts = object2intopenhashmap; +- this.spawnPotential = potentialcalculator; +- this.localMobCapCalculator = localmobcapcalculator; +- this.unmodifiableMobCategoryCounts = Object2IntMaps.unmodifiable(object2intopenhashmap); ++ SpawnState(int spawnableChunkCount, Object2IntOpenHashMap<MobCategory> mobCategoryCounts, PotentialCalculator spawnPotential, LocalMobCapCalculator localMobCapCalculator) { ++ this.spawnableChunkCount = spawnableChunkCount; ++ this.mobCategoryCounts = mobCategoryCounts; ++ this.spawnPotential = spawnPotential; ++ this.localMobCapCalculator = localMobCapCalculator; ++ this.unmodifiableMobCategoryCounts = Object2IntMaps.unmodifiable(mobCategoryCounts); + } + +- private boolean canSpawn(EntityType<?> entitytype, BlockPos blockpos, ChunkAccess chunkaccess) { +- this.lastCheckedPos = blockpos; +- this.lastCheckedType = entitytype; +- MobSpawnSettings.MobSpawnCost mobspawnsettings_mobspawncost = NaturalSpawner.getRoughBiome(blockpos, chunkaccess).getMobSettings().getMobSpawnCost(entitytype); ++ private boolean canSpawn(EntityType<?> entityType, BlockPos pos, ChunkAccess chunk) { ++ this.lastCheckedPos = pos; ++ this.lastCheckedType = entityType; ++ MobSpawnSettings.MobSpawnCost biomesettingsmobs_b = NaturalSpawner.getRoughBiome(pos, chunk).getMobSettings().getMobSpawnCost(entityType); + +- if (mobspawnsettings_mobspawncost == null) { ++ if (biomesettingsmobs_b == null) { + this.lastCharge = 0.0D; + return true; + } else { +- double d0 = mobspawnsettings_mobspawncost.charge(); ++ double d0 = biomesettingsmobs_b.charge(); + + this.lastCharge = d0; +- double d1 = this.spawnPotential.getPotentialEnergyChange(blockpos, d0); ++ double d1 = this.spawnPotential.getPotentialEnergyChange(pos, d0); + +- return d1 <= mobspawnsettings_mobspawncost.energyBudget(); ++ return d1 <= biomesettingsmobs_b.energyBudget(); + } + } + +- private void afterSpawn(Mob mob, ChunkAccess chunkaccess) { +- EntityType<?> entitytype = mob.getType(); +- BlockPos blockpos = mob.blockPosition(); ++ private void afterSpawn(Mob mob, ChunkAccess chunk) { ++ EntityType<?> entitytypes = mob.getType(); ++ BlockPos blockposition = mob.blockPosition(); + double d0; + +- if (blockpos.equals(this.lastCheckedPos) && entitytype == this.lastCheckedType) { ++ if (blockposition.equals(this.lastCheckedPos) && entitytypes == this.lastCheckedType) { + d0 = this.lastCharge; + } else { +- MobSpawnSettings.MobSpawnCost mobspawnsettings_mobspawncost = NaturalSpawner.getRoughBiome(blockpos, chunkaccess).getMobSettings().getMobSpawnCost(entitytype); ++ MobSpawnSettings.MobSpawnCost biomesettingsmobs_b = NaturalSpawner.getRoughBiome(blockposition, chunk).getMobSettings().getMobSpawnCost(entitytypes); + +- if (mobspawnsettings_mobspawncost != null) { +- d0 = mobspawnsettings_mobspawncost.charge(); ++ if (biomesettingsmobs_b != null) { ++ d0 = biomesettingsmobs_b.charge(); + } else { + d0 = 0.0D; + } + } + +- this.spawnPotential.addCharge(blockpos, d0); +- MobCategory mobcategory = entitytype.getCategory(); ++ this.spawnPotential.addCharge(blockposition, d0); ++ MobCategory enumcreaturetype = entitytypes.getCategory(); + +- this.mobCategoryCounts.addTo(mobcategory, 1); +- this.localMobCapCalculator.addMob(new ChunkPos(blockpos), mobcategory); ++ this.mobCategoryCounts.addTo(enumcreaturetype, 1); ++ this.localMobCapCalculator.addMob(new ChunkPos(blockposition), enumcreaturetype); + } + + public int getSpawnableChunkCount() { +@@ -511,10 +536,12 @@ + return this.unmodifiableMobCategoryCounts; + } + +- boolean canSpawnForCategory(MobCategory mobcategory, ChunkPos chunkpos) { +- int i = mobcategory.getMaxInstancesPerChunk() * this.spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER; ++ // CraftBukkit start ++ boolean canSpawnForCategory(MobCategory enumcreaturetype, ChunkPos chunkcoordintpair, int limit) { ++ int i = limit * this.spawnableChunkCount / NaturalSpawner.MAGIC_NUMBER; ++ // CraftBukkit end + +- return this.mobCategoryCounts.getInt(mobcategory) >= i ? false : this.localMobCapCalculator.canSpawn(mobcategory, chunkpos); ++ return this.mobCategoryCounts.getInt(enumcreaturetype) >= i ? false : this.localMobCapCalculator.canSpawn(enumcreaturetype, chunkcoordintpair); + } + } + |