diff --git a/paper-server/patches/sources/net/minecraft/util/SpawnUtil.java.patch b/paper-server/patches/sources/net/minecraft/util/SpawnUtil.java.patch index c10588bdee..803fd149f1 100644 --- a/paper-server/patches/sources/net/minecraft/util/SpawnUtil.java.patch +++ b/paper-server/patches/sources/net/minecraft/util/SpawnUtil.java.patch @@ -1,18 +1,18 @@ --- a/net/minecraft/util/SpawnUtil.java +++ b/net/minecraft/util/SpawnUtil.java -@@ -21,24 +21,31 @@ +@@ -21,24 +21,47 @@ public SpawnUtil() {} public static Optional trySpawnMob(EntityType entityType, EntitySpawnReason reason, ServerLevel world, BlockPos pos, int tries, int horizontalRange, int verticalRange, SpawnUtil.Strategy requirements, boolean requireEmptySpace) { - BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable(); + // CraftBukkit start -+ return SpawnUtil.trySpawnMob(entityType, reason, world, pos, tries, horizontalRange, verticalRange, requirements, requireEmptySpace, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); ++ return SpawnUtil.trySpawnMob(entityType, reason, world, pos, tries, horizontalRange, verticalRange, requirements, requireEmptySpace, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT, null); // Paper - pre creature spawn event + } - for (int l = 0; l < tries; ++l) { - int i1 = Mth.randomBetweenInclusive(world.random, -horizontalRange, horizontalRange); - int j1 = Mth.randomBetweenInclusive(world.random, -horizontalRange, horizontalRange); -+ public static Optional trySpawnMob(EntityType entitytypes, EntitySpawnReason entityspawnreason, ServerLevel worldserver, BlockPos blockposition, int i, int j, int k, SpawnUtil.Strategy spawnutil_a, boolean flag, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) { ++ public static Optional trySpawnMob(EntityType entitytypes, EntitySpawnReason entityspawnreason, ServerLevel worldserver, BlockPos blockposition, int i, int j, int k, SpawnUtil.Strategy spawnutil_a, boolean flag, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason, @javax.annotation.Nullable Runnable onAbort) { // Paper - pre creature spawn event + // CraftBukkit end + BlockPos.MutableBlockPos blockposition_mutableblockposition = blockposition.mutable(); @@ -25,6 +25,22 @@ + blockposition_mutableblockposition.setWithOffset(blockposition, i1, k, j1); + if (worldserver.getWorldBorder().isWithinBounds((BlockPos) blockposition_mutableblockposition) && SpawnUtil.moveToPossibleSpawnPosition(worldserver, k, blockposition_mutableblockposition, spawnutil_a) && (!flag || worldserver.noCollision(entitytypes.getSpawnAABB((double) blockposition_mutableblockposition.getX() + 0.5D, (double) blockposition_mutableblockposition.getY(), (double) blockposition_mutableblockposition.getZ() + 0.5D)))) { ++ // Paper start - PreCreatureSpawnEvent ++ final com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( ++ io.papermc.paper.util.MCUtil.toLocation(worldserver, blockposition), ++ org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(entitytypes), ++ reason ++ ); ++ if (!event.callEvent()) { ++ if (event.shouldAbortSpawn()) { ++ if (onAbort != null) { ++ onAbort.run(); ++ } ++ return Optional.empty(); ++ } ++ break; ++ } ++ // Paper end - PreCreatureSpawnEvent + T t0 = entitytypes.create(worldserver, (Consumer) null, blockposition_mutableblockposition, entityspawnreason, false, false); // CraftBukkit - decompile error + if (t0 != null) { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch index 3045be366e..96cfe9b1a7 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/EntityType.java.patch @@ -54,7 +54,7 @@ } public static Consumer createDefaultStackConfig(Level world, ItemStack stack, @Nullable Player player) { -@@ -464,21 +472,40 @@ +@@ -464,21 +472,50 @@ CustomData customdata = (CustomData) stack.getOrDefault(DataComponents.ENTITY_DATA, CustomData.EMPTY); return !customdata.isEmpty() ? chained.andThen((entity) -> { @@ -82,12 +82,22 @@ + // CraftBukkit start + return this.spawn(world, afterConsumer, pos, reason, alignPosition, invertY, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT); + } -+ + + @Nullable + public T spawn(ServerLevel worldserver, @Nullable Consumer consumer, BlockPos blockposition, EntitySpawnReason entityspawnreason, boolean flag, boolean flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) { + // CraftBukkit end ++ // Paper start - PreCreatureSpawnEvent ++ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( ++ io.papermc.paper.util.MCUtil.toLocation(worldserver, blockposition), ++ org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(this), ++ spawnReason ++ ); ++ if (!event.callEvent()) { ++ return null; ++ } ++ // Paper end - PreCreatureSpawnEvent + T t0 = this.create(worldserver, consumer, blockposition, entityspawnreason, flag, flag1); - ++ if (t0 != null) { - world.addFreshEntityWithPassengers(t0); + // CraftBukkit start @@ -99,7 +109,7 @@ if (t0 instanceof Mob) { Mob entityinsentient = (Mob) t0; -@@ -657,7 +684,7 @@ +@@ -657,7 +694,7 @@ } return entity; @@ -108,7 +118,7 @@ } public static Stream loadEntitiesRecursive(final List entityNbtList, final Level world, final EntitySpawnReason reason) { -@@ -718,7 +745,7 @@ +@@ -718,7 +755,7 @@ @Nullable public T tryCast(Entity obj) { @@ -117,7 +127,7 @@ } @Override -@@ -791,7 +818,7 @@ +@@ -791,7 +828,7 @@ this.canSpawnFarFromPlayer = spawnGroup == MobCategory.CREATURE || spawnGroup == MobCategory.MISC; } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/npc/Villager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/npc/Villager.java.patch index d28a09255d..da2b2d1d8d 100644 --- a/paper-server/patches/sources/net/minecraft/world/entity/npc/Villager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/npc/Villager.java.patch @@ -145,7 +145,7 @@ if (list1.size() >= requiredCount) { - if (!SpawnUtil.trySpawnMob(EntityType.IRON_GOLEM, EntitySpawnReason.MOB_SUMMONED, world, this.blockPosition(), 10, 8, 6, SpawnUtil.Strategy.LEGACY_IRON_GOLEM, false).isEmpty()) { -+ if (!SpawnUtil.trySpawnMob(EntityType.IRON_GOLEM, EntitySpawnReason.MOB_SUMMONED, world, this.blockPosition(), 10, 8, 6, SpawnUtil.Strategy.LEGACY_IRON_GOLEM, false, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_DEFENSE).isEmpty()) { // CraftBukkit ++ if (SpawnUtil.trySpawnMob(EntityType.IRON_GOLEM, EntitySpawnReason.MOB_SUMMONED, world, this.blockPosition(), 10, 8, 6, SpawnUtil.Strategy.LEGACY_IRON_GOLEM, false, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_DEFENSE, () -> {GolemSensor.golemDetected(this);}).isPresent()) { // CraftBukkit // Paper - Set Golem Last Seen to stop it from spawning another one list.forEach(GolemSensor::golemDetected); } } diff --git a/paper-server/patches/sources/net/minecraft/world/level/BaseSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/level/BaseSpawner.java.patch index 9193b7da39..ce9e5d276f 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/BaseSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/BaseSpawner.java.patch @@ -40,7 +40,30 @@ } else { boolean flag = false; RandomSource randomsource = world.getRandom(); -@@ -157,13 +164,26 @@ +@@ -123,8 +130,22 @@ + continue; + } + } else if (!SpawnPlacements.checkSpawnRules((EntityType) optional.get(), world, EntitySpawnReason.SPAWNER, blockposition1, world.getRandom())) { ++ continue; ++ } ++ // Paper start - PreCreatureSpawnEvent ++ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( ++ io.papermc.paper.util.MCUtil.toLocation(world, d0, d1, d2), ++ org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(optional.get()), ++ org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER ++ ); ++ if (!event.callEvent()) { ++ flag = true; ++ if (event.shouldAbortSpawn()) { ++ break; ++ } + continue; + } ++ // Paper end - PreCreatureSpawnEvent + + Entity entity = EntityType.loadEntityRecursive(nbttagcompound, world, EntitySpawnReason.SPAWNER, (entity1) -> { + entity1.moveTo(d0, d1, d2, entity1.getYRot(), entity1.getXRot()); +@@ -157,13 +178,26 @@ ((Mob) entity).finalizeSpawn(world, world.getCurrentDifficultyAt(entity.blockPosition()), EntitySpawnReason.SPAWNER, (SpawnGroupData) null); } @@ -69,7 +92,7 @@ this.delay(world, pos); return; } -@@ -174,7 +194,7 @@ +@@ -174,7 +208,7 @@ ((Mob) entity).spawnAnim(); } diff --git a/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch index 18d4ed97cf..7c479fd1c8 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/NaturalSpawner.java.patch @@ -48,7 +48,22 @@ list.add(enumcreaturetype); } } -@@ -217,10 +238,15 @@ +@@ -207,7 +228,13 @@ + j1 = biomesettingsmobs_c.minCount + world.random.nextInt(1 + biomesettingsmobs_c.maxCount - biomesettingsmobs_c.minCount); + } + +- if (NaturalSpawner.isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2) && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) { ++ // Paper start - PreCreatureSpawnEvent ++ PreSpawnStatus doSpawning = isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2); ++ if (doSpawning == PreSpawnStatus.ABORT) { ++ return; ++ } ++ if (doSpawning == PreSpawnStatus.SUCCESS && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) { ++ // Paper end - PreCreatureSpawnEvent + Mob entityinsentient = NaturalSpawner.getMobForSpawn(world, biomesettingsmobs_c.type); + + if (entityinsentient == null) { +@@ -217,10 +244,15 @@ entityinsentient.moveTo(d0, (double) i, d1, world.random.nextFloat() * 360.0F, 0.0F); if (NaturalSpawner.isValidPositionForMob(world, entityinsentient, d2)) { groupdataentity = entityinsentient.finalizeSpawn(world, world.getCurrentDifficultyAt(entityinsentient.blockPosition()), EntitySpawnReason.NATURAL, groupdataentity); @@ -68,7 +83,41 @@ if (j >= entityinsentient.getMaxSpawnClusterSize()) { return; } -@@ -268,6 +294,7 @@ +@@ -250,10 +282,31 @@ + return squaredDistance <= 576.0D ? false : (world.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()) || world.isNaturalSpawningAllowed((BlockPos) pos)); + } + +- private static boolean isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) { ++ // Paper start - PreCreatureSpawnEvent ++ private enum PreSpawnStatus { ++ FAIL, ++ SUCCESS, ++ CANCELLED, ++ ABORT ++ } ++ private static PreSpawnStatus isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) { ++ // Paper end - PreCreatureSpawnEvent + EntityType entitytypes = spawnEntry.type; + +- return entitytypes.getCategory() == MobCategory.MISC ? false : (!entitytypes.canSpawnFarFromPlayer() && squaredDistance > (double) (entitytypes.getCategory().getDespawnDistance() * entitytypes.getCategory().getDespawnDistance()) ? false : (entitytypes.canSummon() && NaturalSpawner.canSpawnMobAt(world, structureAccessor, chunkGenerator, group, spawnEntry, pos) ? (!SpawnPlacements.isSpawnPositionOk(entitytypes, world, pos) ? false : (!SpawnPlacements.checkSpawnRules(entitytypes, world, EntitySpawnReason.NATURAL, pos, world.random) ? false : world.noCollision(entitytypes.getSpawnAABB((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D)))) : false)); ++ // Paper start - PreCreatureSpawnEvent ++ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( ++ io.papermc.paper.util.MCUtil.toLocation(world, pos), ++ org.bukkit.craftbukkit.entity.CraftEntityType.minecraftToBukkit(entitytypes), SpawnReason.NATURAL ++ ); ++ if (!event.callEvent()) { ++ if (event.shouldAbortSpawn()) { ++ return PreSpawnStatus.ABORT; ++ } ++ return PreSpawnStatus.CANCELLED; ++ } ++ // Paper end - PreCreatureSpawnEvent ++ ++ return entitytypes.getCategory() == MobCategory.MISC ? PreSpawnStatus.FAIL : (!entitytypes.canSpawnFarFromPlayer() && squaredDistance > (double) (entitytypes.getCategory().getDespawnDistance() * entitytypes.getCategory().getDespawnDistance()) ? PreSpawnStatus.FAIL : (entitytypes.canSummon() && NaturalSpawner.canSpawnMobAt(world, structureAccessor, chunkGenerator, group, spawnEntry, pos) ? (!SpawnPlacements.isSpawnPositionOk(entitytypes, world, pos) ? PreSpawnStatus.FAIL : (!SpawnPlacements.checkSpawnRules(entitytypes, world, EntitySpawnReason.NATURAL, pos, world.random) ? PreSpawnStatus.FAIL : world.noCollision(entitytypes.getSpawnAABB((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D)) ? PreSpawnStatus.SUCCESS : PreSpawnStatus.FAIL)) : PreSpawnStatus.FAIL)); // Paper - PreCreatureSpawnEvent + } + + @Nullable +@@ -268,6 +321,7 @@ NaturalSpawner.LOGGER.warn("Can't spawn entity of type: {}", BuiltInRegistries.ENTITY_TYPE.getKey(type)); } catch (Exception exception) { NaturalSpawner.LOGGER.warn("Failed to create mob", exception); @@ -76,7 +125,7 @@ } return null; -@@ -356,6 +383,7 @@ +@@ -356,6 +410,7 @@ entity = biomesettingsmobs_c.type.create(world.getLevel(), EntitySpawnReason.NATURAL); } catch (Exception exception) { NaturalSpawner.LOGGER.warn("Failed to create mob", exception); @@ -84,7 +133,7 @@ continue; } -@@ -369,7 +397,7 @@ +@@ -369,7 +424,7 @@ if (entityinsentient.checkSpawnRules(world, EntitySpawnReason.CHUNK_GENERATION) && entityinsentient.checkSpawnObstruction(world)) { groupdataentity = entityinsentient.finalizeSpawn(world, world.getCurrentDifficultyAt(entityinsentient.blockPosition()), EntitySpawnReason.CHUNK_GENERATION, groupdataentity); @@ -93,7 +142,7 @@ flag = true; } } -@@ -482,10 +510,12 @@ +@@ -482,10 +537,12 @@ return this.unmodifiableMobCategoryCounts; }