2021-06-14 07:40:21 +02:00
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Aikar <aikar@aikar.co>
Date: Sun, 14 Jan 2018 17:01:31 -0500
Subject: [PATCH] PreCreatureSpawnEvent
Adds an event to fire before an Entity is created, so that plugins that need to cancel
CreatureSpawnEvent can do so from this event instead.
Cancelling CreatureSpawnEvent rapidly causes a lot of garbage collection and CPU waste
as it's done after the Entity object has been fully created.
Mob Limiting plugins and blanket "ban this type of monster" plugins should use this event
instead and save a lot of server resources.
See: https://github.com/PaperMC/Paper/issues/917
2022-06-07 23:54:21 +02:00
diff --git a/src/main/java/net/minecraft/util/SpawnUtil.java b/src/main/java/net/minecraft/util/SpawnUtil.java
2024-01-22 18:04:55 +01:00
index b77ebe04f1018962b85110258c8a0a2db8612485..1a0cd6ae172c911d3b4cc0f82e253536a4898ca9 100644
2022-06-07 23:54:21 +02:00
--- a/src/main/java/net/minecraft/util/SpawnUtil.java
+++ b/src/main/java/net/minecraft/util/SpawnUtil.java
2023-06-07 21:37:42 +02:00
@@ -22,10 +22,10 @@ public class SpawnUtil {
2022-06-07 23:54:21 +02:00
public static <T extends Mob> Optional<T> trySpawnMob(EntityType<T> entityType, MobSpawnType reason, ServerLevel world, BlockPos pos, int tries, int horizontalRange, int verticalRange, SpawnUtil.Strategy requirements) {
// CraftBukkit start
- return SpawnUtil.trySpawnMob(entityType, reason, world, pos, tries, horizontalRange, verticalRange, requirements, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT);
+ return SpawnUtil.trySpawnMob(entityType, reason, world, pos, tries, horizontalRange, verticalRange, requirements, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DEFAULT, null); // Paper
}
- public static <T extends Mob> Optional<T> trySpawnMob(EntityType<T> entitytypes, MobSpawnType enummobspawn, ServerLevel worldserver, BlockPos blockposition, int i, int j, int k, SpawnUtil.Strategy spawnutil_a, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason) {
+ public static <T extends Mob> Optional<T> trySpawnMob(EntityType<T> entitytypes, MobSpawnType enummobspawn, ServerLevel worldserver, BlockPos blockposition, int i, int j, int k, SpawnUtil.Strategy spawnutil_a, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason reason, @javax.annotation.Nullable Runnable onAbort) { // Paper
// CraftBukkit end
BlockPos.MutableBlockPos blockposition_mutableblockposition = blockposition.mutable();
2023-06-07 21:37:42 +02:00
@@ -35,6 +35,26 @@ public class SpawnUtil {
2022-06-07 23:54:21 +02:00
blockposition_mutableblockposition.setWithOffset(blockposition, i1, k, j1);
if (worldserver.getWorldBorder().isWithinBounds((BlockPos) blockposition_mutableblockposition) && SpawnUtil.moveToPossibleSpawnPosition(worldserver, k, blockposition_mutableblockposition, spawnutil_a)) {
2024-01-22 18:04:55 +01:00
+ // Paper start - PreCreatureSpawnEvent
2022-06-07 23:54:21 +02:00
+ String key = EntityType.getKey(entitytypes).getPath();
+ org.bukkit.entity.EntityType type = org.bukkit.entity.EntityType.fromName(key);
+
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
+ event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
2022-10-24 21:43:46 +02:00
+ io.papermc.paper.util.MCUtil.toLocation(worldserver, blockposition),
2022-06-07 23:54:21 +02:00
+ type,
+ reason
+ );
+ if (!event.callEvent()) {
+ if (event.shouldAbortSpawn()) {
+ if (onAbort != null) {
+ onAbort.run();
+ }
+ return Optional.empty();
+ }
+ break;
+ }
2024-01-22 18:04:55 +01:00
+ // Paper end - PreCreatureSpawnEvent
2022-12-07 19:52:24 +01:00
T t0 = entitytypes.create(worldserver, (CompoundTag) null, null, blockposition_mutableblockposition, enummobspawn, false, false); // CraftBukkit - decompile error
2022-06-07 23:54:21 +02:00
if (t0 != null) {
2021-06-14 07:40:21 +02:00
diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java
2024-01-22 18:04:55 +01:00
index 382b55167dede435b034866bd394455f0f6f2a00..bd4ae65070eb4b98dae0529b5985f80093bf8185 100644
2021-06-14 07:40:21 +02:00
--- a/src/main/java/net/minecraft/world/entity/EntityType.java
+++ b/src/main/java/net/minecraft/world/entity/EntityType.java
2023-12-05 23:12:48 +01:00
@@ -418,6 +418,20 @@ public class EntityType<T extends Entity> implements FeatureElement, EntityTypeT
2021-06-14 07:40:21 +02:00
@Nullable
2022-12-07 19:52:24 +01:00
public T spawn(ServerLevel worldserver, @Nullable CompoundTag nbttagcompound, @Nullable Consumer<T> consumer, BlockPos blockposition, MobSpawnType enummobspawn, boolean flag, boolean flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) {
// CraftBukkit end
2024-01-22 18:04:55 +01:00
+ // Paper start - PreCreatureSpawnEvent
2021-06-14 07:40:21 +02:00
+ org.bukkit.entity.EntityType type = org.bukkit.entity.EntityType.fromName(EntityType.getKey(this).getPath());
+ if (type != null) {
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
+ event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
2022-10-24 21:43:46 +02:00
+ io.papermc.paper.util.MCUtil.toLocation(worldserver, blockposition),
2021-06-14 07:40:21 +02:00
+ type,
+ spawnReason
+ );
+ if (!event.callEvent()) {
+ return null;
+ }
+ }
2024-01-22 18:04:55 +01:00
+ // Paper end - PreCreatureSpawnEvent
2022-12-07 19:52:24 +01:00
T t0 = this.create(worldserver, nbttagcompound, consumer, blockposition, enummobspawn, flag, flag1);
2021-06-14 07:40:21 +02:00
if (t0 != null) {
diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java
2023-12-05 23:12:48 +01:00
index a0a313fa5e7e4e1973c020d0262e34381a19dea7..0429b927e63ec12f53a6ce1ebe1e64d99bf7e129 100644
2021-06-14 07:40:21 +02:00
--- a/src/main/java/net/minecraft/world/entity/npc/Villager.java
+++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java
2023-09-21 23:04:51 +02:00
@@ -975,7 +975,7 @@ public class Villager extends AbstractVillager implements ReputationEventHandler
2022-06-07 23:54:21 +02:00
}).limit(5L).collect(Collectors.toList());
2021-06-14 07:40:21 +02:00
2022-06-07 23:54:21 +02:00
if (list1.size() >= requiredCount) {
2023-09-21 23:04:51 +02:00
- if (!SpawnUtil.trySpawnMob(EntityType.IRON_GOLEM, MobSpawnType.MOB_SUMMONED, world, this.blockPosition(), 10, 8, 6, SpawnUtil.Strategy.LEGACY_IRON_GOLEM, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_DEFENSE).isEmpty()) { // CraftBukkit
2022-06-07 23:54:21 +02:00
+ if (SpawnUtil.trySpawnMob(EntityType.IRON_GOLEM, MobSpawnType.MOB_SUMMONED, world, this.blockPosition(), 10, 8, 6, SpawnUtil.Strategy.LEGACY_IRON_GOLEM, 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);
}
}
2021-06-14 07:40:21 +02:00
diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java
2024-01-22 18:04:55 +01:00
index 393b77043cbaf58200fca6e56c22c36aa2aa2cfb..db4beb22cf54bb3b53561ec0fe06209c478977ff 100644
2021-06-14 07:40:21 +02:00
--- a/src/main/java/net/minecraft/world/level/BaseSpawner.java
+++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java
2023-12-05 23:12:48 +01:00
@@ -130,6 +130,27 @@ public abstract class BaseSpawner {
2021-11-23 15:03:50 +01:00
} else if (!SpawnPlacements.checkSpawnRules((EntityType) optional.get(), world, MobSpawnType.SPAWNER, blockposition1, world.getRandom())) {
continue;
}
2024-01-22 18:04:55 +01:00
+ // Paper start - PreCreatureSpawnEvent
2021-06-14 07:40:21 +02:00
+ EntityType<?> entityType = optional.get();
+ String key = EntityType.getKey(entityType).getPath();
+
+ org.bukkit.entity.EntityType type = org.bukkit.entity.EntityType.fromName(key);
+ if (type != null) {
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
+ event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
2022-10-24 21:43:46 +02:00
+ io.papermc.paper.util.MCUtil.toLocation(world, d0, d1, d2),
2021-06-14 07:40:21 +02:00
+ type,
+ org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER
+ );
+ if (!event.callEvent()) {
+ flag = true;
+ if (event.shouldAbortSpawn()) {
+ break;
+ }
+ continue;
+ }
+ }
2024-01-22 18:04:55 +01:00
+ // Paper end - PreCreatureSpawnEvent
2021-11-23 15:03:50 +01:00
2021-06-14 07:40:21 +02:00
Entity entity = EntityType.loadEntityRecursive(nbttagcompound, world, (entity1) -> {
entity1.moveTo(d0, d1, d2, entity1.getYRot(), entity1.getXRot());
diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
2024-01-22 18:04:55 +01:00
index 92e76dd39dc3575e9466031dd799080a98ad8b8d..449a811202c9dea62bcf4a2f483e08a9bc1d0129 100644
2021-06-14 07:40:21 +02:00
--- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java
+++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java
2022-12-07 19:52:24 +01:00
@@ -213,7 +213,13 @@ public final class NaturalSpawner {
2021-06-14 07:40:21 +02:00
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)) {
2024-01-22 18:04:55 +01:00
+ // Paper start - PreCreatureSpawnEvent
2023-08-21 09:44:47 +02:00
+ PreSpawnStatus doSpawning = isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2);
+ if (doSpawning == PreSpawnStatus.ABORT) {
2021-06-14 07:40:21 +02:00
+ return;
+ }
2023-08-21 09:44:47 +02:00
+ if (doSpawning == PreSpawnStatus.SUCCESS && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) {
2024-01-22 18:04:55 +01:00
+ // Paper end - PreCreatureSpawnEvent
2021-06-14 07:40:21 +02:00
Mob entityinsentient = NaturalSpawner.getMobForSpawn(world, biomesettingsmobs_c.type);
if (entityinsentient == null) {
2023-08-21 09:44:47 +02:00
@@ -261,19 +267,44 @@ public final class NaturalSpawner {
2022-03-01 06:43:03 +01:00
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));
2021-06-14 07:40:21 +02:00
}
2022-06-07 23:54:21 +02:00
- private static boolean isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) {
2024-01-22 18:04:55 +01:00
+ // Paper start - PreCreatureSpawnEvent
2023-08-21 09:44:47 +02:00
+ 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) {
2024-01-22 18:04:55 +01:00
+ // Paper end - PreCreatureSpawnEvent
2021-06-14 07:40:21 +02:00
EntityType<?> entitytypes = spawnEntry.type;
2024-01-22 18:04:55 +01:00
+ // Paper start - PreCreatureSpawnEvent
2021-06-14 07:40:21 +02:00
+ com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event;
+ org.bukkit.entity.EntityType type = org.bukkit.entity.EntityType.fromName(EntityType.getKey(entitytypes).getPath());
+ if (type != null) {
+ event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent(
2022-10-24 21:43:46 +02:00
+ io.papermc.paper.util.MCUtil.toLocation(world, pos),
2021-06-14 07:40:21 +02:00
+ type, SpawnReason.NATURAL
+ );
+ if (!event.callEvent()) {
+ if (event.shouldAbortSpawn()) {
2023-08-21 09:44:47 +02:00
+ return PreSpawnStatus.ABORT; // Paper
2021-06-14 07:40:21 +02:00
+ }
2023-08-21 09:44:47 +02:00
+ return PreSpawnStatus.CANCELLED; // Paper
2021-06-14 07:40:21 +02:00
+ }
+ }
2024-01-22 18:04:55 +01:00
+ // Paper end - PreCreatureSpawnEvent
2021-06-14 07:40:21 +02:00
if (entitytypes.getCategory() == MobCategory.MISC) {
2023-08-21 09:44:47 +02:00
- return false;
2024-01-22 18:04:55 +01:00
+ return PreSpawnStatus.FAIL; // Paper - PreCreatureSpawnEvent
2021-06-14 07:40:21 +02:00
} else if (!entitytypes.canSpawnFarFromPlayer() && squaredDistance > (double) (entitytypes.getCategory().getDespawnDistance() * entitytypes.getCategory().getDespawnDistance())) {
2023-08-21 09:44:47 +02:00
- return false;
2024-01-22 18:04:55 +01:00
+ return PreSpawnStatus.FAIL; // Paper - PreCreatureSpawnEvent
2023-08-21 09:44:47 +02:00
} else if (entitytypes.canSummon() && NaturalSpawner.canSpawnMobAt(world, structureAccessor, chunkGenerator, group, spawnEntry, pos)) {
SpawnPlacements.Type entitypositiontypes_surface = SpawnPlacements.getPlacementType(entitytypes);
- return !NaturalSpawner.isSpawnPositionOk(entitypositiontypes_surface, world, pos, entitytypes) ? false : (!SpawnPlacements.checkSpawnRules(entitytypes, world, MobSpawnType.NATURAL, pos, world.random) ? false : world.noCollision(entitytypes.getAABB((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D)));
2024-01-22 18:04:55 +01:00
+ boolean isValid = !NaturalSpawner.isSpawnPositionOk(entitypositiontypes_surface, world, pos, entitytypes) ? false : (!SpawnPlacements.checkSpawnRules(entitytypes, world, MobSpawnType.NATURAL, pos, world.random) ? false : world.noCollision(entitytypes.getAABB((double) pos.getX() + 0.5D, (double) pos.getY(), (double) pos.getZ() + 0.5D))); // Paper - PreCreatureSpawnEvent
+ return isValid ? PreSpawnStatus.SUCCESS : PreSpawnStatus.FAIL; // Paper - PreCreatureSpawnEvent
2023-08-21 09:44:47 +02:00
} else {
- return false;
2024-01-22 18:04:55 +01:00
+ return PreSpawnStatus.FAIL; // Paper - PreCreatureSpawnEvent
2023-08-21 09:44:47 +02:00
}
}