From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 From: Aikar 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 diff --git a/src/main/java/net/minecraft/world/entity/EntityType.java b/src/main/java/net/minecraft/world/entity/EntityType.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/EntityType.java +++ b/src/main/java/net/minecraft/world/entity/EntityType.java @@ -0,0 +0,0 @@ import net.minecraft.nbt.ListTag; import net.minecraft.network.chat.Component; import net.minecraft.network.chat.TranslatableComponent; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MCUtil; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.BlockTags; @@ -0,0 +0,0 @@ public class EntityType { @Nullable public T spawnCreature(ServerLevel worldserver, @Nullable CompoundTag nbttagcompound, @Nullable Component ichatbasecomponent, @Nullable Player entityhuman, BlockPos blockposition, MobSpawnType enummobspawn, boolean flag, boolean flag1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) { + // Paper start - Call PreCreatureSpawnEvent + 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( + MCUtil.toLocation(worldserver, blockposition), + type, + spawnReason + ); + if (!event.callEvent()) { + return null; + } + } + // Paper end T t0 = this.create(worldserver, nbttagcompound, ichatbasecomponent, entityhuman, blockposition, enummobspawn, flag, flag1); if (t0 != null) { diff --git a/src/main/java/net/minecraft/world/entity/ai/sensing/GolemSensor.java b/src/main/java/net/minecraft/world/entity/ai/sensing/GolemSensor.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/ai/sensing/GolemSensor.java +++ b/src/main/java/net/minecraft/world/entity/ai/sensing/GolemSensor.java @@ -0,0 +0,0 @@ public class GolemSensor extends Sensor { Optional> optional = entityliving.getBrain().getMemory(MemoryModuleType.MOBS); if (optional.isPresent()) { - boolean flag = ((List) optional.get()).stream().anyMatch((entityliving1) -> { - return entityliving1.getEntityType().equals(EntityType.IRON_GOLEM); + boolean flag = optional.get().stream().anyMatch((entityliving1) -> { // Paper - decompile fixes + return entityliving1.getType().equals(EntityType.IRON_GOLEM); }); if (flag) { @@ -0,0 +0,0 @@ public class GolemSensor extends Sensor { } } + public static void setDetectedRecently(LivingEntity entityLiving) { golemDetected(entityLiving); } // Paper - OBFHELPER public static void golemDetected(LivingEntity entityliving) { entityliving.getBrain().setMemoryWithExpiry(MemoryModuleType.GOLEM_DETECTED_RECENTLY, true, 600L); } diff --git a/src/main/java/net/minecraft/world/entity/npc/Villager.java b/src/main/java/net/minecraft/world/entity/npc/Villager.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/entity/npc/Villager.java +++ b/src/main/java/net/minecraft/world/entity/npc/Villager.java @@ -0,0 +0,0 @@ import net.minecraft.network.protocol.game.DebugPackets; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; +import net.minecraft.server.MCUtil; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvent; @@ -0,0 +0,0 @@ public class Villager extends AbstractVillager implements ReputationEventHandler BlockPos blockposition1 = this.findSpawnPositionForGolemInColumn(blockposition, d0, d1); if (blockposition1 != null) { + // Paper start - Call PreCreatureSpawnEvent + com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent event; + event = new com.destroystokyo.paper.event.entity.PreCreatureSpawnEvent( + MCUtil.toLocation(level, blockposition1), + org.bukkit.entity.EntityType.IRON_GOLEM, + org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.VILLAGE_DEFENSE + ); + if (!event.callEvent()) { + if (event.shouldAbortSpawn()) { + GolemSensor.golemDetected(this); // Set Golem Last Seen to stop it from spawning another one + return null; + } + break; + } + // Paper end IronGolem entityirongolem = (IronGolem) EntityType.IRON_GOLEM.create(world, (CompoundTag) null, (Component) null, (Player) null, blockposition1, MobSpawnType.MOB_SUMMONED, false, false); if (entityirongolem != null) { diff --git a/src/main/java/net/minecraft/world/level/BaseSpawner.java b/src/main/java/net/minecraft/world/level/BaseSpawner.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/BaseSpawner.java +++ b/src/main/java/net/minecraft/world/level/BaseSpawner.java @@ -0,0 +0,0 @@ import net.minecraft.core.particles.ParticleTypes; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MCUtil; import net.minecraft.server.level.ServerLevel; import net.minecraft.util.StringUtil; import net.minecraft.util.WeighedRandom; @@ -0,0 +0,0 @@ public abstract class BaseSpawner { ServerLevel worldserver = (ServerLevel) world; if (SpawnPlacements.checkSpawnRules((EntityType) optional.get(), worldserver, MobSpawnType.SPAWNER, new BlockPos(d3, d4, d5), world.getRandom())) { + // Paper start + 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( + MCUtil.toLocation(world, d3, d4, d5), + type, + org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPAWNER + ); + if (!event.callEvent()) { + flag = true; + if (event.shouldAbortSpawn()) { + break; + } + continue; + } + } + // Paper end Entity entity = EntityType.loadEntityRecursive(nbttagcompound, world, (entity1) -> { entity1.moveTo(d3, d4, d5, entity1.yRot, entity1.xRot); return entity1; diff --git a/src/main/java/net/minecraft/world/level/NaturalSpawner.java b/src/main/java/net/minecraft/world/level/NaturalSpawner.java index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 100644 --- a/src/main/java/net/minecraft/world/level/NaturalSpawner.java +++ b/src/main/java/net/minecraft/world/level/NaturalSpawner.java @@ -0,0 +0,0 @@ import net.minecraft.core.Direction; import net.minecraft.core.Position; import net.minecraft.core.Registry; import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.MCUtil; import net.minecraft.server.level.ServerLevel; import net.minecraft.tags.BlockTags; import net.minecraft.tags.FluidTags; @@ -0,0 +0,0 @@ public final class NaturalSpawner { j1 = biomesettingsmobs_c.minCount + world.random.nextInt(1 + biomesettingsmobs_c.maxCount - biomesettingsmobs_c.minCount); } - if (isValidSpawnPostitionForType(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2) && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) { + // Paper start + Boolean doSpawning = a(world, group, structuremanager, chunkgenerator, biomesettingsmobs_c, blockposition_mutableblockposition, d2); + if (doSpawning == null) { + return; + } + if (doSpawning && checker.test(biomesettingsmobs_c.type, blockposition_mutableblockposition, chunk)) { + // Paper end Mob entityinsentient = getMobForSpawn(world, biomesettingsmobs_c.type); + if (entityinsentient == null) { return; } @@ -0,0 +0,0 @@ public final class NaturalSpawner { } } - private static boolean isValidSpawnPostitionForType(ServerLevel world, MobCategory group, StructureFeatureManager structureAccessor, ChunkGenerator chunkGenerator, MobSpawnSettings.SpawnerData spawnEntry, BlockPos.MutableBlockPos pos, double squaredDistance) { - EntityType entitytypes = spawnEntry.type; + private static Boolean a(ServerLevel worldserver, MobCategory enumcreaturetype, StructureFeatureManager structuremanager, ChunkGenerator chunkgenerator, MobSpawnSettings.SpawnerData biomesettingsmobs_c, BlockPos.MutableBlockPos blockposition_mutableblockposition, double d0) { // Paper + EntityType entitytypes = biomesettingsmobs_c.type; + // Paper start + 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( + MCUtil.toLocation(worldserver, blockposition_mutableblockposition), + type, SpawnReason.NATURAL + ); + if (!event.callEvent()) { + if (event.shouldAbortSpawn()) { + return null; + } + return false; + } + } + // Paper end if (entitytypes.getCategory() == MobCategory.MISC) { return false; - } else if (!entitytypes.canSpawnFarFromPlayer() && squaredDistance > (double) (entitytypes.getCategory().getDespawnDistance() * entitytypes.getCategory().getDespawnDistance())) { + } else if (!entitytypes.canSpawnFarFromPlayer() && d0 > (double) (entitytypes.getCategory().getDespawnDistance() * entitytypes.getCategory().getDespawnDistance())) { return false; - } else if (entitytypes.canSummon() && canSpawnMobAt(world, structureAccessor, chunkGenerator, group, spawnEntry, (BlockPos) pos)) { + } else if (entitytypes.canSummon() && canSpawnMobAt(worldserver, structuremanager, chunkgenerator, enumcreaturetype, biomesettingsmobs_c, (BlockPos) blockposition_mutableblockposition)) { SpawnPlacements.Type entitypositiontypes_surface = SpawnPlacements.getPlacementType(entitytypes); - return !isSpawnPositionOk(entitypositiontypes_surface, (LevelReader) 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))); + return !isSpawnPositionOk(entitypositiontypes_surface, (LevelReader) worldserver, blockposition_mutableblockposition, entitytypes) ? false : (!SpawnPlacements.checkSpawnRules(entitytypes, worldserver, MobSpawnType.NATURAL, blockposition_mutableblockposition, worldserver.random) ? false : worldserver.noCollision(entitytypes.getAABB((double) blockposition_mutableblockposition.getX() + 0.5D, (double) blockposition_mutableblockposition.getY(), (double) blockposition_mutableblockposition.getZ() + 0.5D))); } else { return false; }