From 07642b457ecccf71d22f6f2c5fd06da599bb2073 Mon Sep 17 00:00:00 2001 From: Nassim Jahnke <nassim@njahnke.dev> Date: Sat, 14 Dec 2024 12:36:08 +0100 Subject: [PATCH] More entity classes --- .../world/entity/LightningBolt.java.patch | 138 +++++ .../net/minecraft/world/entity/Mob.java.patch | 428 ++++++++++++++++ .../world/entity/NeutralMob.java.patch | 69 +++ .../entity/OminousItemSpawner.java.patch | 20 +- .../world/entity/Shearable.java.patch | 7 +- .../world/entity/TamableAnimal.java.patch | 82 +++ .../world/entity/LightningBolt.java.patch | 160 ------ .../net/minecraft/world/entity/Mob.java.patch | 472 ------------------ .../world/entity/NeutralMob.java.patch | 86 ---- .../world/entity/PathfinderMob.java.patch | 12 - .../world/entity/TamableAnimal.java.patch | 85 ---- 11 files changed, 731 insertions(+), 828 deletions(-) create mode 100644 paper-server/patches/sources/net/minecraft/world/entity/LightningBolt.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch create mode 100644 paper-server/patches/sources/net/minecraft/world/entity/NeutralMob.java.patch rename paper-server/patches/{unapplied => sources}/net/minecraft/world/entity/OminousItemSpawner.java.patch (70%) rename paper-server/patches/{unapplied => sources}/net/minecraft/world/entity/Shearable.java.patch (65%) create mode 100644 paper-server/patches/sources/net/minecraft/world/entity/TamableAnimal.java.patch delete mode 100644 paper-server/patches/unapplied/net/minecraft/world/entity/LightningBolt.java.patch delete mode 100644 paper-server/patches/unapplied/net/minecraft/world/entity/Mob.java.patch delete mode 100644 paper-server/patches/unapplied/net/minecraft/world/entity/NeutralMob.java.patch delete mode 100644 paper-server/patches/unapplied/net/minecraft/world/entity/PathfinderMob.java.patch delete mode 100644 paper-server/patches/unapplied/net/minecraft/world/entity/TamableAnimal.java.patch diff --git a/paper-server/patches/sources/net/minecraft/world/entity/LightningBolt.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/LightningBolt.java.patch new file mode 100644 index 0000000000..632c00d653 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/LightningBolt.java.patch @@ -0,0 +1,138 @@ +--- a/net/minecraft/world/entity/LightningBolt.java ++++ b/net/minecraft/world/entity/LightningBolt.java +@@ -39,6 +_,7 @@ + private ServerPlayer cause; + private final Set<Entity> hitEntities = Sets.newHashSet(); + private int blocksSetOnFire; ++ public boolean isEffect; // Paper - Properly handle lightning effects api + + public LightningBolt(EntityType<? extends LightningBolt> entityType, Level level) { + super(entityType, level); +@@ -76,7 +_,7 @@ + @Override + public void tick() { + super.tick(); +- if (this.life == 2) { ++ if (!this.isEffect && this.life == 2) { // Paper - Properly handle lightning effects api + if (this.level().isClientSide()) { + this.level() + .playLocalSound( +@@ -107,7 +_,7 @@ + } + + this.powerLightningRod(); +- clearCopperOnLightningStrike(this.level(), this.getStrikePosition()); ++ clearCopperOnLightningStrike(this.level(), this.getStrikePosition(), this); // Paper - Call EntityChangeBlockEvent + this.gameEvent(GameEvent.LIGHTNING_STRIKE); + } + } +@@ -130,7 +_,7 @@ + } + } + +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + } else if (this.life < -this.random.nextInt(10)) { + this.flashes--; + this.life = 1; +@@ -139,10 +_,10 @@ + } + } + +- if (this.life >= 0) { ++ if (this.life >= 0 && !this.isEffect) { // CraftBukkit - add !this.visualOnly // Paper - Properly handle lightning effects api + if (!(this.level() instanceof ServerLevel)) { + this.level().setSkyFlashTime(2); +- } else if (!this.visualOnly) { ++ } else if (!this.visualOnly && !this.isEffect) { // Paper - Properly handle lightning effects api + List<Entity> entities = this.level() + .getEntities( + this, +@@ -172,22 +_,30 @@ + BlockPos blockPos = this.blockPosition(); + BlockState state = BaseFireBlock.getState(this.level(), blockPos); + if (this.level().getBlockState(blockPos).isAir() && state.canSurvive(this.level(), blockPos)) { +- this.level().setBlockAndUpdate(blockPos, state); +- this.blocksSetOnFire++; ++ // CraftBukkit start - add "!visualOnly" ++ if (!this.visualOnly && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level(), blockPos, this).isCancelled()) { ++ this.level().setBlockAndUpdate(blockPos, state); ++ this.blocksSetOnFire++; ++ } ++ // CraftBukkit end + } + + for (int i = 0; i < extraIgnitions; i++) { + BlockPos blockPos1 = blockPos.offset(this.random.nextInt(3) - 1, this.random.nextInt(3) - 1, this.random.nextInt(3) - 1); + state = BaseFireBlock.getState(this.level(), blockPos1); + if (this.level().getBlockState(blockPos1).isAir() && state.canSurvive(this.level(), blockPos1)) { +- this.level().setBlockAndUpdate(blockPos1, state); +- this.blocksSetOnFire++; ++ // CraftBukkit start - add "!visualOnly" ++ if (!this.visualOnly && !org.bukkit.craftbukkit.event.CraftEventFactory.callBlockIgniteEvent(this.level(), blockPos1, this).isCancelled()) { ++ this.level().setBlockAndUpdate(blockPos1, state); ++ this.blocksSetOnFire++; ++ } ++ // CraftBukkit end + } + } + } + } + +- private static void clearCopperOnLightningStrike(Level level, BlockPos pos) { ++ private static void clearCopperOnLightningStrike(Level level, BlockPos pos, Entity lightning) { // Paper - Call EntityChangeBlockEvent + BlockState blockState = level.getBlockState(pos); + BlockPos blockPos; + BlockState blockState1; +@@ -200,22 +_,27 @@ + } + + if (blockState1.getBlock() instanceof WeatheringCopper) { +- level.setBlockAndUpdate(blockPos, WeatheringCopper.getFirst(level.getBlockState(blockPos))); ++ // Paper start - Call EntityChangeBlockEvent ++ BlockState newBlockState = WeatheringCopper.getFirst(level.getBlockState(blockPos)); ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(lightning, blockPos, newBlockState)) { ++ level.setBlockAndUpdate(blockPos, newBlockState); ++ } ++ // Paper end - Call EntityChangeBlockEvent + BlockPos.MutableBlockPos mutableBlockPos = pos.mutable(); + int i = level.random.nextInt(3) + 3; + + for (int i1 = 0; i1 < i; i1++) { + int i2 = level.random.nextInt(8) + 1; +- randomWalkCleaningCopper(level, blockPos, mutableBlockPos, i2); ++ randomWalkCleaningCopper(level, blockPos, mutableBlockPos, i2, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent + } + } + } + +- private static void randomWalkCleaningCopper(Level level, BlockPos pos, BlockPos.MutableBlockPos mutable, int steps) { ++ private static void randomWalkCleaningCopper(Level level, BlockPos pos, BlockPos.MutableBlockPos mutable, int steps, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent + mutable.set(pos); + + for (int i = 0; i < steps; i++) { +- Optional<BlockPos> optional = randomStepCleaningCopper(level, mutable); ++ Optional<BlockPos> optional = randomStepCleaningCopper(level, mutable, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent + if (optional.isEmpty()) { + break; + } +@@ -224,11 +_,17 @@ + } + } + +- private static Optional<BlockPos> randomStepCleaningCopper(Level level, BlockPos pos) { ++ private static Optional<BlockPos> randomStepCleaningCopper(Level level, BlockPos pos, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent + for (BlockPos blockPos : BlockPos.randomInCube(level.random, 10, pos, 1)) { + BlockState blockState = level.getBlockState(blockPos); + if (blockState.getBlock() instanceof WeatheringCopper) { +- WeatheringCopper.getPrevious(blockState).ifPresent(blockState1 -> level.setBlockAndUpdate(blockPos, blockState1)); ++ // Paper start - call EntityChangeBlockEvent ++ WeatheringCopper.getPrevious(blockState).ifPresent(blockState1 -> { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(lightning, blockPos, blockState1)) { ++ level.setBlockAndUpdate(blockPos, blockState1); ++ } ++ }); ++ // Paper end - call EntityChangeBlockEvent + level.levelEvent(3002, blockPos, -1); + return Optional.of(blockPos); + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch new file mode 100644 index 0000000000..3670fec552 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/Mob.java.patch @@ -0,0 +1,428 @@ +--- a/net/minecraft/world/entity/Mob.java ++++ b/net/minecraft/world/entity/Mob.java +@@ -84,6 +_,18 @@ + import net.minecraft.world.level.storage.loot.parameters.LootContextParams; + import net.minecraft.world.phys.AABB; + ++// CraftBukkit start ++import org.bukkit.craftbukkit.event.CraftEventFactory; ++import org.bukkit.craftbukkit.entity.CraftLivingEntity; ++import org.bukkit.event.entity.CreatureSpawnEvent; ++import org.bukkit.event.entity.EntityRemoveEvent; ++import org.bukkit.event.entity.EntityTargetLivingEntityEvent; ++import org.bukkit.event.entity.EntityTargetEvent; ++import org.bukkit.event.entity.EntityTransformEvent; ++import org.bukkit.event.entity.EntityUnleashEvent; ++import org.bukkit.event.entity.EntityUnleashEvent.UnleashReason; ++// CraftBukkit end ++ + public abstract class Mob extends LivingEntity implements EquipmentUser, Leashable, Targeting { + private static final EntityDataAccessor<Byte> DATA_MOB_FLAGS_ID = SynchedEntityData.defineId(Mob.class, EntityDataSerializers.BYTE); + private static final int MOB_FLAG_NO_AI = 1; +@@ -112,6 +_,7 @@ + private final BodyRotationControl bodyRotationControl; + protected PathNavigation navigation; + public GoalSelector goalSelector; ++ @Nullable public net.minecraft.world.entity.ai.goal.FloatGoal goalFloat; // Paper - Allow nerfed mobs to jump and float + public GoalSelector targetSelector; + @Nullable + private LivingEntity target; +@@ -131,6 +_,7 @@ + private Leashable.LeashData leashData; + private BlockPos restrictCenter = BlockPos.ZERO; + private float restrictRadius = -1.0F; ++ public boolean aware = true; // CraftBukkit + + protected Mob(EntityType<? extends Mob> entityType, Level level) { + super(entityType, level); +@@ -150,6 +_,12 @@ + } + } + ++ // CraftBukkit start ++ public void setPersistenceRequired(boolean persistenceRequired) { ++ this.persistenceRequired = persistenceRequired; ++ } ++ // CraftBukkit end ++ + protected void registerGoals() { + } + +@@ -230,7 +_,40 @@ + } + + public void setTarget(@Nullable LivingEntity target) { ++ // CraftBukkit start - fire event ++ this.setTarget(target, EntityTargetEvent.TargetReason.UNKNOWN, true); ++ } ++ ++ public boolean setTarget(LivingEntity target, EntityTargetEvent.TargetReason reason, boolean fireEvent) { ++ if (this.getTarget() == target) { ++ return false; ++ } ++ if (fireEvent) { ++ if (reason == EntityTargetEvent.TargetReason.UNKNOWN && this.getTarget() != null && target == null) { ++ reason = this.getTarget().isAlive() ? EntityTargetEvent.TargetReason.FORGOT_TARGET : EntityTargetEvent.TargetReason.TARGET_DIED; ++ } ++ if (reason == EntityTargetEvent.TargetReason.UNKNOWN) { ++ this.level().getCraftServer().getLogger().log(java.util.logging.Level.WARNING, "Unknown target reason, please report on the issue tracker", new Exception()); ++ } ++ CraftLivingEntity ctarget = null; ++ if (target != null) { ++ ctarget = (CraftLivingEntity) target.getBukkitEntity(); ++ } ++ EntityTargetLivingEntityEvent event = new EntityTargetLivingEntityEvent(this.getBukkitEntity(), ctarget, reason); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ return false; ++ } ++ ++ if (event.getTarget() != null) { ++ target = ((CraftLivingEntity) event.getTarget()).getHandle(); ++ } else { ++ target = null; ++ } ++ } + this.target = target; ++ return true; ++ // CraftBukkit end + } + + @Override +@@ -354,6 +_,12 @@ + return null; + } + ++ // CraftBukkit start - Add delegate method ++ public SoundEvent getAmbientSound0() { ++ return this.getAmbientSound(); ++ } ++ // CraftBukkit end ++ + @Override + public void addAdditionalSaveData(CompoundTag compound) { + super.addAdditionalSaveData(compound); +@@ -413,13 +_,25 @@ + if (this.isNoAi()) { + compound.putBoolean("NoAI", this.isNoAi()); + } ++ compound.putBoolean("Bukkit.Aware", this.aware); // CraftBukkit + } + + @Override + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); +- this.setCanPickUpLoot(compound.getBoolean("CanPickUpLoot")); +- this.persistenceRequired = compound.getBoolean("PersistenceRequired"); ++ // CraftBukkit start - If looting or persistence is false only use it if it was set after we started using it ++ if (compound.contains("CanPickUpLoot", 99)) { ++ boolean data = compound.getBoolean("CanPickUpLoot"); ++ if (isLevelAtLeast(compound, 1) || data) { ++ this.setCanPickUpLoot(data); ++ } ++ } ++ ++ boolean data = compound.getBoolean("PersistenceRequired"); ++ if (isLevelAtLeast(compound, 1) || data) { ++ this.persistenceRequired = data; ++ } ++ // CraftBukkit end + if (compound.contains("ArmorItems", 9)) { + ListTag list = compound.getList("ArmorItems", 10); + +@@ -472,13 +_,18 @@ + this.readLeashData(compound); + this.setLeftHanded(compound.getBoolean("LeftHanded")); + if (compound.contains("DeathLootTable", 8)) { +- this.lootTable = Optional.of(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(compound.getString("DeathLootTable")))); ++ this.lootTable = Optional.ofNullable(ResourceLocation.tryParse(compound.getString("DeathLootTable"))).map((rs) -> ResourceKey.create(Registries.LOOT_TABLE, rs)); // Paper - Validate ResourceLocation + } else { + this.lootTable = Optional.empty(); + } + + this.lootTableSeed = compound.getLong("DeathLootTableSeed"); + this.setNoAi(compound.getBoolean("NoAI")); ++ // CraftBukkit start ++ if (compound.contains("Bukkit.Aware")) { ++ this.aware = compound.getBoolean("Bukkit.Aware"); ++ } ++ // CraftBukkit end + } + + @Override +@@ -540,6 +_,11 @@ + && !itemEntity.getItem().isEmpty() + && !itemEntity.hasPickUpDelay() + && this.wantsToPickUp(serverLevel, itemEntity.getItem())) { ++ // Paper start - Item#canEntityPickup ++ if (!itemEntity.canMobPickup) { ++ continue; ++ } ++ // Paper end - Item#canEntityPickup + this.pickUpItem(serverLevel, itemEntity); + } + } +@@ -554,18 +_,24 @@ + + protected void pickUpItem(ServerLevel level, ItemEntity entity) { + ItemStack item = entity.getItem(); +- ItemStack itemStack = this.equipItemIfPossible(level, item.copy()); ++ ItemStack itemStack = this.equipItemIfPossible(level, item.copy(), entity); // CraftBukkit - add item + if (!itemStack.isEmpty()) { + this.onItemPickup(entity); + this.take(entity, itemStack.getCount()); + item.shrink(itemStack.getCount()); + if (item.isEmpty()) { +- entity.discard(); ++ entity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause + } + } + } + + public ItemStack equipItemIfPossible(ServerLevel level, ItemStack stack) { ++ // CraftBukkit start - add item ++ return this.equipItemIfPossible(level, stack, null); ++ } ++ ++ public ItemStack equipItemIfPossible(ServerLevel level, ItemStack stack, ItemEntity entity) { ++ // CraftBukkit end + EquipmentSlot equipmentSlotForItem = this.getEquipmentSlotForItem(stack); + ItemStack itemBySlot = this.getItemBySlot(equipmentSlotForItem); + boolean canReplaceCurrentItem = this.canReplaceCurrentItem(stack, itemBySlot, equipmentSlotForItem); +@@ -575,10 +_,18 @@ + canReplaceCurrentItem = itemBySlot.isEmpty(); + } + +- if (canReplaceCurrentItem && this.canHoldItem(stack)) { ++ // CraftBukkit start ++ boolean canPickup = canReplaceCurrentItem && this.canHoldItem(stack); ++ if (entity != null) { ++ canPickup = !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entity, 0, !canPickup).isCancelled(); ++ } ++ if (canPickup) { ++ // CraftBukkit end + double d = this.getEquipmentDropChance(equipmentSlotForItem); + if (!itemBySlot.isEmpty() && Math.max(this.random.nextFloat() - 0.1F, 0.0F) < d) { ++ this.forceDrops = true; // CraftBukkit + this.spawnAtLocation(level, itemBySlot); ++ this.forceDrops = false; // CraftBukkit + } + + ItemStack itemStack = equipmentSlotForItem.limit(stack); +@@ -703,22 +_,29 @@ + @Override + public void checkDespawn() { + if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) { +- this.discard(); ++ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + } else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) { +- Entity nearestPlayer = this.level().getNearestPlayer(this, -1.0); ++ Entity nearestPlayer = this.level().getNearestPlayer(this, -1.0, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper - Affects Spawning API + if (nearestPlayer != null) { +- double d = nearestPlayer.distanceToSqr(this); +- int despawnDistance = this.getType().getCategory().getDespawnDistance(); +- int i = despawnDistance * despawnDistance; +- if (d > i && this.removeWhenFarAway(d)) { +- this.discard(); +- } ++ // Paper start - Configurable despawn distances ++ final io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DespawnRangePair despawnRangePair = this.level().paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory()); ++ final io.papermc.paper.configuration.type.DespawnRange.Shape shape = this.level().paperConfig().entities.spawning.despawnRangeShape; ++ final double dy = Math.abs(nearestPlayer.getY() - this.getY()); ++ final double dySqr = Math.pow(dy, 2); ++ final double dxSqr = Math.pow(nearestPlayer.getX() - this.getX(), 2); ++ final double dzSqr = Math.pow(nearestPlayer.getZ() - this.getZ(), 2); ++ final double distanceSquared = dxSqr + dzSqr + dySqr; ++ // Despawn if hard/soft limit is exceeded ++ if (despawnRangePair.hard().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy) && this.removeWhenFarAway(distanceSquared)) { ++ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause ++ } + +- int noDespawnDistance = this.getType().getCategory().getNoDespawnDistance(); +- int i1 = noDespawnDistance * noDespawnDistance; +- if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && d > i1 && this.removeWhenFarAway(d)) { +- this.discard(); +- } else if (d < i1) { ++ if (despawnRangePair.soft().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy)) { ++ if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && this.removeWhenFarAway(distanceSquared)) { ++ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause ++ } ++ } else { ++ // Paper end - Configurable despawn distances + this.noActionTime = 0; + } + } +@@ -730,6 +_,15 @@ + @Override + protected final void serverAiStep() { + this.noActionTime++; ++ // Paper start - Allow nerfed mobs to jump and float ++ if (!this.aware) { ++ if (goalFloat != null) { ++ if (goalFloat.canUse()) goalFloat.tick(); ++ this.getJumpControl().tick(); ++ } ++ return; ++ } ++ // Paper end - Allow nerfed mobs to jump and float + ProfilerFiller profilerFiller = Profiler.get(); + profilerFiller.push("sensing"); + this.sensing.tick(); +@@ -908,26 +_,40 @@ + + @Override + public void setItemSlot(EquipmentSlot slot, ItemStack stack) { ++ // Paper start - Fix silent equipment change ++ setItemSlot(slot, stack, false); ++ } ++ ++ @Override ++ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) { ++ // Paper end - Fix silent equipment change + this.verifyEquippedItem(stack); + switch (slot.getType()) { + case HAND: +- this.onEquipItem(slot, this.handItems.set(slot.getIndex(), stack), stack); ++ this.onEquipItem(slot, this.handItems.set(slot.getIndex(), stack), stack, silent); // Paper - Fix silent equipment change + break; + case HUMANOID_ARMOR: +- this.onEquipItem(slot, this.armorItems.set(slot.getIndex(), stack), stack); ++ this.onEquipItem(slot, this.armorItems.set(slot.getIndex(), stack), stack, silent); // Paper - Fix silent equipment change + break; + case ANIMAL_ARMOR: + ItemStack itemStack = this.bodyArmorItem; + this.bodyArmorItem = stack; +- this.onEquipItem(slot, itemStack, stack); ++ this.onEquipItem(slot, itemStack, stack, silent); // Paper - Fix silent equipment change + } + } ++ ++ // Paper start ++ protected boolean shouldSkipLoot(EquipmentSlot slot) { // method to avoid to fallback into the global mob loot logic (i.e fox) ++ return false; ++ } ++ // Paper end + + @Override + protected void dropCustomDeathLoot(ServerLevel level, DamageSource damageSource, boolean recentlyHit) { + super.dropCustomDeathLoot(level, damageSource, recentlyHit); + + for (EquipmentSlot equipmentSlot : EquipmentSlot.VALUES) { ++ if (this.shouldSkipLoot(equipmentSlot)) continue; // Paper + ItemStack itemBySlot = this.getItemBySlot(equipmentSlot); + float equipmentDropChance = this.getEquipmentDropChance(equipmentSlot); + if (equipmentDropChance != 0.0F) { +@@ -951,7 +_,13 @@ + } + + this.spawnAtLocation(level, itemBySlot); ++ if (this.clearEquipmentSlots) { // Paper + this.setItemSlot(equipmentSlot, ItemStack.EMPTY); ++ // Paper start ++ } else { ++ this.clearedEquipmentSlots.add(enumitemslot); ++ } ++ // Paper end + } + } + } +@@ -1269,6 +_,22 @@ + public <T extends Mob> T convertTo( + EntityType<T> entityType, ConversionParams conversionParams, EntitySpawnReason spawnReason, ConversionParams.AfterConversion<T> afterConversion + ) { ++ return this.convertTo(entityType, conversionParams, spawnReason, afterConversion, EntityTransformEvent.TransformReason.UNKNOWN, CreatureSpawnEvent.SpawnReason.DEFAULT); ++ } ++ ++ @Nullable ++ public <T extends Mob> T convertTo( ++ EntityType<T> entityType, ConversionParams conversionParams, EntitySpawnReason spawnReason, ConversionParams.AfterConversion<T> afterConversion, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason creatureSpawnReason ++ ) { ++ // Paper start - entity zap event - allow cancellation of conversion post creation ++ return this.convertTo(entityType, conversionParams, spawnReason, e -> { afterConversion.finalizeConversion(e); return true; }, transformReason, spawnReason); ++ } ++ @Nullable ++ public <T extends Mob> T convertTo( ++ EntityType<T> entityType, ConversionParams conversionParams, EntitySpawnReason spawnReason, ConversionParams.CancellingAfterConversion<T> afterConversion, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason creatureSpawnReason ++ ) { ++ // Paper end - entity zap event - allow cancellation of conversion post creation ++ // CraftBukkit end + if (this.isRemoved()) { + return null; + } else { +@@ -1277,13 +_,23 @@ + return null; + } else { + conversionParams.type().convert(this, mob, conversionParams); +- afterConversion.finalizeConversion(mob); ++ if (!afterConversion.finalizeConversionOrCancel(mob)) return null; // Paper - entity zap event - return null if conversion was cancelled ++ // CraftBukkit start ++ if (transformReason == null) { ++ // Special handling for slime split and pig lightning ++ return mob; ++ } ++ ++ if (CraftEventFactory.callEntityTransformEvent(this, mob, transformReason).isCancelled()) { ++ return null; ++ } ++ // CraftBukkit end + if (this.level() instanceof ServerLevel serverLevel) { +- serverLevel.addFreshEntity(mob); ++ serverLevel.addFreshEntity(mob, creatureSpawnReason); // CraftBukkit + } + + if (conversionParams.type().shouldDiscardAfterConversion()) { +- this.discard(); ++ this.discard(EntityRemoveEvent.Cause.TRANSFORMATION); // CraftBukkit - add Bukkit remove cause + } + + return mob; +@@ -1293,7 +_,20 @@ + + @Nullable + public <T extends Mob> T convertTo(EntityType<T> entityType, ConversionParams coversionParams, ConversionParams.AfterConversion<T> afterConversion) { +- return this.convertTo(entityType, coversionParams, EntitySpawnReason.CONVERSION, afterConversion); ++ // CraftBukkit start ++ return this.convertTo(entityType, coversionParams, afterConversion, EntityTransformEvent.TransformReason.UNKNOWN, CreatureSpawnEvent.SpawnReason.DEFAULT); ++ } ++ ++ @Nullable ++ public <T extends Mob> T convertTo(EntityType<T> entityType, ConversionParams coversionParams, ConversionParams.AfterConversion<T> afterConversion, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason creatureSpawnReason) { ++ // Paper start - entity zap event - allow cancellation of conversion post creation ++ return this.convertTo(entityType, coversionParams, e -> { afterConversion.finalizeConversion(e); return true; }, transformReason, creatureSpawnReason); ++ } ++ @Nullable ++ public <T extends Mob> T convertTo(EntityType<T> entityType, ConversionParams coversionParams, ConversionParams.CancellingAfterConversion<T> afterConversion, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason creatureSpawnReason) { ++ // Paper start - entity zap event - allow cancellation of conversion post creation ++ return this.convertTo(entityType, coversionParams, EntitySpawnReason.CONVERSION, afterConversion, transformReason, creatureSpawnReason); ++ // CraftBukkit end + } + + @Nullable +@@ -1329,7 +_,17 @@ + public boolean startRiding(Entity entity, boolean force) { + boolean flag = super.startRiding(entity, force); + if (flag && this.isLeashed()) { +- this.dropLeash(); ++ // Paper start - Expand EntityUnleashEvent ++ EntityUnleashEvent event = new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.UNKNOWN, true); ++ if (!event.callEvent()) { ++ return flag; ++ } ++ if (event.isDropLeash()) { ++ this.dropLeash(); ++ } else { ++ this.removeLeash(); ++ } ++ // Paper end - Expand EntityUnleashEvent + } + + return flag; +@@ -1412,7 +_,7 @@ + float knockback = this.getKnockback(source, damageSource); + if (knockback > 0.0F && source instanceof LivingEntity livingEntity) { + livingEntity.knockback( +- knockback * 0.5F, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)) ++ knockback * 0.5F, Mth.sin(this.getYRot() * (float) (Math.PI / 180.0)), -Mth.cos(this.getYRot() * (float) (Math.PI / 180.0)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK // CraftBukkit // Paper - knockback events + ); + this.setDeltaMovement(this.getDeltaMovement().multiply(0.6, 1.0, 0.6)); + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/NeutralMob.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/NeutralMob.java.patch new file mode 100644 index 0000000000..06fd0f09c7 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/NeutralMob.java.patch @@ -0,0 +1,69 @@ +--- a/net/minecraft/world/entity/NeutralMob.java ++++ b/net/minecraft/world/entity/NeutralMob.java +@@ -39,18 +_,11 @@ + } else { + UUID uuid = tag.getUUID("AngryAt"); + this.setPersistentAngerTarget(uuid); +- Entity entity = ((ServerLevel)level).getEntity(uuid); +- if (entity != null) { +- if (entity instanceof Mob mob) { +- this.setTarget(mob); +- this.setLastHurtByMob(mob); +- } +- +- if (entity instanceof Player player) { +- this.setTarget(player); +- this.setLastHurtByPlayer(player); +- } +- } ++ // Paper - Prevent entity loading causing async lookups; Moved diff to separate method ++ // If this entity already survived its first tick, e.g. is loaded and ticked in sync, actively ++ // tick the initial persistent anger. ++ // If not, let the first tick on the baseTick call the method later down the line. ++ if (this instanceof Entity entity && !entity.firstTick) this.tickInitialPersistentAnger(level); + } + } + } +@@ -104,7 +_,7 @@ + default void stopBeingAngry() { + this.setLastHurtByMob(null); + this.setPersistentAngerTarget(null); +- this.setTarget(null); ++ this.setTarget(null, org.bukkit.event.entity.EntityTargetEvent.TargetReason.FORGOT_TARGET, true); // CraftBukkit + this.setRemainingPersistentAngerTime(0); + } + +@@ -117,8 +_,33 @@ + + void setTarget(@Nullable LivingEntity livingEntity); + ++ boolean setTarget(@Nullable LivingEntity entityliving, org.bukkit.event.entity.EntityTargetEvent.TargetReason reason, boolean fireEvent); // CraftBukkit ++ + boolean canAttack(LivingEntity entity); + + @Nullable + LivingEntity getTarget(); ++ ++ // Paper start - Prevent entity loading causing async lookups ++ // Update last hurt when ticking ++ default void tickInitialPersistentAnger(Level level) { ++ UUID uuid = getPersistentAngerTarget(); ++ if (uuid == null) { ++ return; ++ } ++ ++ Entity entity = ((ServerLevel)level).getEntity(uuid); ++ if (entity != null) { ++ if (entity instanceof Mob mob) { ++ this.setTarget(mob, org.bukkit.event.entity.EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit ++ this.setLastHurtByMob(mob); ++ } ++ ++ if (entity instanceof Player player) { ++ this.setTarget(player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit ++ this.setLastHurtByPlayer(player); ++ } ++ } ++ } ++ // Paper end - Prevent entity loading causing async lookups + } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/OminousItemSpawner.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/OminousItemSpawner.java.patch similarity index 70% rename from paper-server/patches/unapplied/net/minecraft/world/entity/OminousItemSpawner.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/OminousItemSpawner.java.patch index c390374ad2..10e7665ce7 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/OminousItemSpawner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/OminousItemSpawner.java.patch @@ -1,25 +1,25 @@ --- a/net/minecraft/world/entity/OminousItemSpawner.java +++ b/net/minecraft/world/entity/OminousItemSpawner.java -@@ -76,7 +76,7 @@ - entity = this.spawnProjectile(serverLevel, projectileItem, itemStack); +@@ -76,7 +_,7 @@ + entity = this.spawnProjectile(serverLevel, projectileItem, item); } else { - entity = new ItemEntity(serverLevel, this.getX(), this.getY(), this.getZ(), itemStack); + entity = new ItemEntity(serverLevel, this.getX(), this.getY(), this.getZ(), item); - serverLevel.addFreshEntity(entity); + serverLevel.addFreshEntity(entity, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.OMINOUS_ITEM_SPAWNER); // Paper - fixes and addition to spawn reason API } serverLevel.levelEvent(3021, this.blockPosition(), 1); -@@ -90,7 +90,7 @@ - ProjectileItem.DispenseConfig dispenseConfig = item.createDispenseConfig(); - dispenseConfig.overrideDispenseEvent().ifPresent(dispenseEvent -> world.levelEvent(dispenseEvent, this.blockPosition(), 0)); +@@ -90,7 +_,7 @@ + ProjectileItem.DispenseConfig dispenseConfig = projectileItem.createDispenseConfig(); + dispenseConfig.overrideDispenseEvent().ifPresent(i -> level.levelEvent(i, this.blockPosition(), 0)); Direction direction = Direction.DOWN; - Projectile projectile = Projectile.spawnProjectileUsingShoot( + Projectile projectile = Projectile.spawnProjectileUsingShootDelayed( // Paper - fixes and addition to spawn reason API - item.asProjectile(world, this.position(), stack, direction), - world, + projectileItem.asProjectile(level, this.position(), stack, direction), + level, stack, -@@ -99,7 +99,7 @@ - (double)direction.getStepZ(), +@@ -99,7 +_,7 @@ + direction.getStepZ(), dispenseConfig.power(), dispenseConfig.uncertainty() - ); diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/Shearable.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/Shearable.java.patch similarity index 65% rename from paper-server/patches/unapplied/net/minecraft/world/entity/Shearable.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/Shearable.java.patch index aa779fc65d..177b7c0bc7 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/Shearable.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/Shearable.java.patch @@ -1,13 +1,14 @@ --- a/net/minecraft/world/entity/Shearable.java +++ b/net/minecraft/world/entity/Shearable.java -@@ -5,7 +5,15 @@ +@@ -5,7 +_,16 @@ import net.minecraft.world.item.ItemStack; public interface Shearable { -+ default void shear(ServerLevel world, SoundSource soundCategory, ItemStack shears, java.util.List<net.minecraft.world.item.ItemStack> drops) { this.shear(world, soundCategory, shears); } // Paper - Add drops to shear events - void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears); ++ default void shear(ServerLevel level, SoundSource soundSource, ItemStack shears, java.util.List<net.minecraft.world.item.ItemStack> drops) { this.shear(level, soundSource, shears); } // Paper - Add drops to shear events + void shear(ServerLevel level, SoundSource soundSource, ItemStack shears); boolean readyForShearing(); ++ + net.minecraft.world.level.Level level(); // Shearable API - expose default level needed for shearing. + + // Paper start - custom shear drops; ensure all implementing entities override this diff --git a/paper-server/patches/sources/net/minecraft/world/entity/TamableAnimal.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/TamableAnimal.java.patch new file mode 100644 index 0000000000..ca11667ad6 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/TamableAnimal.java.patch @@ -0,0 +1,82 @@ +--- a/net/minecraft/world/entity/TamableAnimal.java ++++ b/net/minecraft/world/entity/TamableAnimal.java +@@ -57,7 +_,7 @@ + compound.putUUID("Owner", this.getOwnerUUID()); + } + +- compound.putBoolean("Sitting", this.orderedToSit); ++ compound.putBoolean("Sitting", this.orderedToSit);f + } + + @Override +@@ -84,7 +_,7 @@ + } + + this.orderedToSit = compound.getBoolean("Sitting"); +- this.setInSittingPose(this.orderedToSit); ++ this.setInSittingPose(this.orderedToSit, false); // Paper - Add EntityToggleSitEvent + } + + @Override +@@ -95,8 +_,16 @@ + @Override + public boolean handleLeashAtDistance(Entity leashHolder, float distance) { + if (this.isInSittingPose()) { +- if (distance > 10.0F) { +- this.dropLeash(); ++ if (distance > (float) this.level().paperConfig().misc.maxLeashDistance.or(Leashable.LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance ++ // Paper start - Expand EntityUnleashEvent ++ org.bukkit.event.entity.EntityUnleashEvent event = new org.bukkit.event.entity.EntityUnleashEvent(this.getBukkitEntity(), org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.DISTANCE, true); ++ if (!event.callEvent()) return false; ++ if (event.isDropLeash()) { ++ this.dropLeash(); ++ } else { ++ this.removeLeash(); ++ } ++ // Paper end - Expand EntityUnleashEvent + } + + return false; +@@ -155,6 +_,12 @@ + } + + public void setInSittingPose(boolean sitting) { ++ // Paper start - Add EntityToggleSitEvent ++ this.setInSittingPose(sitting, true); ++ } ++ public void setInSittingPose(boolean sitting, boolean callEvent) { ++ if (callEvent && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), sitting).callEvent()) return; ++ // Paper end - Add EntityToggleSitEvent + byte b = this.entityData.get(DATA_FLAGS_ID); + if (sitting) { + this.entityData.set(DATA_FLAGS_ID, (byte)(b | 1)); +@@ -227,7 +_,12 @@ + if (this.level() instanceof ServerLevel serverLevel + && serverLevel.getGameRules().getBoolean(GameRules.RULE_SHOWDEATHMESSAGES) + && this.getOwner() instanceof ServerPlayer serverPlayer) { +- serverPlayer.sendSystemMessage(this.getCombatTracker().getDeathMessage()); ++ // Paper start - Add TameableDeathMessageEvent ++ io.papermc.paper.event.entity.TameableDeathMessageEvent event = new io.papermc.paper.event.entity.TameableDeathMessageEvent((org.bukkit.entity.Tameable) getBukkitEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(this.getCombatTracker().getDeathMessage())); ++ if (event.callEvent()) { ++ serverPlayer.sendSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.deathMessage())); ++ } ++ // Paper end - Add TameableDeathMessageEvent + } + + super.die(cause); +@@ -270,7 +_,14 @@ + if (!this.canTeleportTo(new BlockPos(x, y, z))) { + return false; + } else { +- this.moveTo(x + 0.5, y, z + 0.5, this.getYRot(), this.getXRot()); ++ // CraftBukkit start ++ org.bukkit.event.entity.EntityTeleportEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTeleportEvent(this, x + 0.5D, y, z + 0.5D); ++ if (event.isCancelled() || event.getTo() == null) { // Paper - prevent NP on null event to location ++ return false; ++ } ++ org.bukkit.Location to = event.getTo(); ++ this.moveTo(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch()); ++ // CraftBukkit end + this.navigation.stop(); + return true; + } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/LightningBolt.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/LightningBolt.java.patch deleted file mode 100644 index 1dc2b6bf90..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/LightningBolt.java.patch +++ /dev/null @@ -1,160 +0,0 @@ ---- a/net/minecraft/world/entity/LightningBolt.java -+++ b/net/minecraft/world/entity/LightningBolt.java -@@ -30,6 +30,10 @@ - import net.minecraft.world.level.gameevent.GameEvent; - import net.minecraft.world.phys.AABB; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class LightningBolt extends Entity { - -@@ -44,6 +48,7 @@ - private ServerPlayer cause; - private final Set<Entity> hitEntities = Sets.newHashSet(); - private int blocksSetOnFire; -+ public boolean isEffect; // Paper - Properly handle lightning effects api - - public LightningBolt(EntityType<? extends LightningBolt> type, Level world) { - super(type, world); -@@ -82,7 +87,7 @@ - @Override - public void tick() { - super.tick(); -- if (this.life == 2) { -+ if (!this.isEffect && this.life == 2) { // Paper - Properly handle lightning effects api - if (this.level().isClientSide()) { - this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.LIGHTNING_BOLT_THUNDER, SoundSource.WEATHER, 10000.0F, 0.8F + this.random.nextFloat() * 0.2F, false); - this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.LIGHTNING_BOLT_IMPACT, SoundSource.WEATHER, 2.0F, 0.5F + this.random.nextFloat() * 0.2F, false); -@@ -94,7 +99,7 @@ - } - - this.powerLightningRod(); -- LightningBolt.clearCopperOnLightningStrike(this.level(), this.getStrikePosition()); -+ LightningBolt.clearCopperOnLightningStrike(this.level(), this.getStrikePosition(), this); // Paper - Call EntityChangeBlockEvent - this.gameEvent(GameEvent.LIGHTNING_STRIKE); - } - } -@@ -120,7 +125,7 @@ - } - } - -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - } else if (this.life < -this.random.nextInt(10)) { - --this.flashes; - this.life = 1; -@@ -129,7 +134,7 @@ - } - } - -- if (this.life >= 0) { -+ if (this.life >= 0 && !this.isEffect) { // CraftBukkit - add !this.visualOnly // Paper - Properly handle lightning effects api - if (!(this.level() instanceof ServerLevel)) { - this.level().setSkyFlashTime(2); - } else if (!this.visualOnly) { -@@ -158,7 +163,7 @@ - } - - private void spawnFire(int spreadAttempts) { -- if (!this.visualOnly) { -+ if (!this.visualOnly && !this.isEffect) { // Paper - Properly handle lightning effects api - Level world = this.level(); - - if (world instanceof ServerLevel) { -@@ -169,8 +174,12 @@ - BlockState iblockdata = BaseFireBlock.getState(this.level(), blockposition); - - if (this.level().getBlockState(blockposition).isAir() && iblockdata.canSurvive(this.level(), blockposition)) { -- this.level().setBlockAndUpdate(blockposition, iblockdata); -- ++this.blocksSetOnFire; -+ // CraftBukkit start - add "!visualOnly" -+ if (!this.visualOnly && !CraftEventFactory.callBlockIgniteEvent(this.level(), blockposition, this).isCancelled()) { -+ this.level().setBlockAndUpdate(blockposition, iblockdata); -+ ++this.blocksSetOnFire; -+ } -+ // CraftBukkit end - } - - for (int j = 0; j < spreadAttempts; ++j) { -@@ -178,8 +187,12 @@ - - iblockdata = BaseFireBlock.getState(this.level(), blockposition1); - if (this.level().getBlockState(blockposition1).isAir() && iblockdata.canSurvive(this.level(), blockposition1)) { -- this.level().setBlockAndUpdate(blockposition1, iblockdata); -- ++this.blocksSetOnFire; -+ // CraftBukkit start - add "!visualOnly" -+ if (!this.visualOnly && !CraftEventFactory.callBlockIgniteEvent(this.level(), blockposition1, this).isCancelled()) { -+ this.level().setBlockAndUpdate(blockposition1, iblockdata); -+ ++this.blocksSetOnFire; -+ } -+ // CraftBukkit end - } - } - -@@ -190,7 +203,7 @@ - - } - -- private static void clearCopperOnLightningStrike(Level world, BlockPos pos) { -+ private static void clearCopperOnLightningStrike(Level world, BlockPos pos, Entity lightning) { // Paper - Call EntityChangeBlockEvent - BlockState iblockdata = world.getBlockState(pos); - BlockPos blockposition1; - BlockState iblockdata1; -@@ -204,24 +217,29 @@ - } - - if (iblockdata1.getBlock() instanceof WeatheringCopper) { -- world.setBlockAndUpdate(blockposition1, WeatheringCopper.getFirst(world.getBlockState(blockposition1))); -+ // Paper start - Call EntityChangeBlockEvent -+ BlockState newBlock = WeatheringCopper.getFirst(world.getBlockState(blockposition1)); -+ if (CraftEventFactory.callEntityChangeBlockEvent(lightning, blockposition1, newBlock)) { -+ world.setBlockAndUpdate(blockposition1, newBlock); -+ } -+ // Paper end - Call EntityChangeBlockEvent - BlockPos.MutableBlockPos blockposition_mutableblockposition = pos.mutable(); - int i = world.random.nextInt(3) + 3; - - for (int j = 0; j < i; ++j) { - int k = world.random.nextInt(8) + 1; - -- LightningBolt.randomWalkCleaningCopper(world, blockposition1, blockposition_mutableblockposition, k); -+ LightningBolt.randomWalkCleaningCopper(world, blockposition1, blockposition_mutableblockposition, k, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent - } - - } - } - -- private static void randomWalkCleaningCopper(Level world, BlockPos pos, BlockPos.MutableBlockPos mutablePos, int count) { -+ private static void randomWalkCleaningCopper(Level world, BlockPos pos, BlockPos.MutableBlockPos mutablePos, int count, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent - mutablePos.set(pos); - - for (int j = 0; j < count; ++j) { -- Optional<BlockPos> optional = LightningBolt.randomStepCleaningCopper(world, mutablePos); -+ Optional<BlockPos> optional = LightningBolt.randomStepCleaningCopper(world, mutablePos, lightning); // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent - - if (optional.isEmpty()) { - break; -@@ -232,7 +250,7 @@ - - } - -- private static Optional<BlockPos> randomStepCleaningCopper(Level world, BlockPos pos) { -+ private static Optional<BlockPos> randomStepCleaningCopper(Level world, BlockPos pos, Entity lightning) { // Paper - transmit LightningBolt instance to call EntityChangeBlockEvent - Iterator iterator = BlockPos.randomInCube(world.random, 10, pos, 1).iterator(); - - BlockPos blockposition1; -@@ -247,8 +265,10 @@ - iblockdata = world.getBlockState(blockposition1); - } while (!(iblockdata.getBlock() instanceof WeatheringCopper)); - -+ BlockPos blockposition1Final = blockposition1; // CraftBukkit - decompile error - WeatheringCopper.getPrevious(iblockdata).ifPresent((iblockdata1) -> { -- world.setBlockAndUpdate(blockposition1, iblockdata1); -+ if (CraftEventFactory.callEntityChangeBlockEvent(lightning, blockposition1Final, iblockdata1)) // Paper - call EntityChangeBlockEvent -+ world.setBlockAndUpdate(blockposition1Final, iblockdata1); // CraftBukkit - decompile error - }); - world.levelEvent(3002, blockposition1, -1); - return Optional.of(blockposition1); diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/Mob.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/Mob.java.patch deleted file mode 100644 index aeaafc3a1b..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/Mob.java.patch +++ /dev/null @@ -1,472 +0,0 @@ ---- a/net/minecraft/world/entity/Mob.java -+++ b/net/minecraft/world/entity/Mob.java -@@ -84,6 +84,17 @@ - import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets; - import net.minecraft.world.level.storage.loot.parameters.LootContextParams; - import net.minecraft.world.phys.AABB; -+// CraftBukkit start -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+import org.bukkit.craftbukkit.entity.CraftLivingEntity; -+import org.bukkit.event.entity.CreatureSpawnEvent; -+import org.bukkit.event.entity.EntityRemoveEvent; -+import org.bukkit.event.entity.EntityTargetLivingEntityEvent; -+import org.bukkit.event.entity.EntityTargetEvent; -+import org.bukkit.event.entity.EntityTransformEvent; -+import org.bukkit.event.entity.EntityUnleashEvent; -+import org.bukkit.event.entity.EntityUnleashEvent.UnleashReason; -+// CraftBukkit end - - public abstract class Mob extends LivingEntity implements EquipmentUser, Leashable, Targeting { - -@@ -112,6 +123,7 @@ - private final BodyRotationControl bodyRotationControl; - protected PathNavigation navigation; - public GoalSelector goalSelector; -+ @Nullable public net.minecraft.world.entity.ai.goal.FloatGoal goalFloat; // Paper - Allow nerfed mobs to jump and float - public GoalSelector targetSelector; - @Nullable - private LivingEntity target; -@@ -132,6 +144,8 @@ - private BlockPos restrictCenter; - private float restrictRadius; - -+ public boolean aware = true; // CraftBukkit -+ - protected Mob(EntityType<? extends Mob> type, Level world) { - super(type, world); - this.handItems = NonNullList.withSize(2, ItemStack.EMPTY); -@@ -157,8 +171,14 @@ - if (world instanceof ServerLevel) { - this.registerGoals(); - } -+ -+ } - -+ // CraftBukkit start -+ public void setPersistenceRequired(boolean persistenceRequired) { -+ this.persistenceRequired = persistenceRequired; - } -+ // CraftBukkit end - - protected void registerGoals() {} - -@@ -264,13 +284,44 @@ - - @Nullable - protected final LivingEntity getTargetFromBrain() { -- return (LivingEntity) this.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse((Object) null); -+ return (LivingEntity) this.getBrain().getMemory(MemoryModuleType.ATTACK_TARGET).orElse(null); // CraftBukkit - decompile error - } - - public void setTarget(@Nullable LivingEntity target) { -- this.target = target; -+ // CraftBukkit start - fire event -+ this.setTarget(target, EntityTargetEvent.TargetReason.UNKNOWN, true); - } - -+ public boolean setTarget(LivingEntity entityliving, EntityTargetEvent.TargetReason reason, boolean fireEvent) { -+ if (this.getTarget() == entityliving) return false; -+ if (fireEvent) { -+ if (reason == EntityTargetEvent.TargetReason.UNKNOWN && this.getTarget() != null && entityliving == null) { -+ reason = this.getTarget().isAlive() ? EntityTargetEvent.TargetReason.FORGOT_TARGET : EntityTargetEvent.TargetReason.TARGET_DIED; -+ } -+ if (reason == EntityTargetEvent.TargetReason.UNKNOWN) { -+ this.level().getCraftServer().getLogger().log(java.util.logging.Level.WARNING, "Unknown target reason, please report on the issue tracker", new Exception()); -+ } -+ CraftLivingEntity ctarget = null; -+ if (entityliving != null) { -+ ctarget = (CraftLivingEntity) entityliving.getBukkitEntity(); -+ } -+ EntityTargetLivingEntityEvent event = new EntityTargetLivingEntityEvent(this.getBukkitEntity(), ctarget, reason); -+ this.level().getCraftServer().getPluginManager().callEvent(event); -+ if (event.isCancelled()) { -+ return false; -+ } -+ -+ if (event.getTarget() != null) { -+ entityliving = ((CraftLivingEntity) event.getTarget()).getHandle(); -+ } else { -+ entityliving = null; -+ } -+ } -+ this.target = entityliving; -+ return true; -+ // CraftBukkit end -+ } -+ - @Override - public boolean canAttackType(EntityType<?> type) { - return type != EntityType.GHAST; -@@ -399,6 +450,12 @@ - return null; - } - -+ // CraftBukkit start - Add delegate method -+ public SoundEvent getAmbientSound0() { -+ return this.getAmbientSound(); -+ } -+ // CraftBukkit end -+ - @Override - public void addAdditionalSaveData(CompoundTag nbt) { - super.addAdditionalSaveData(nbt); -@@ -473,13 +530,25 @@ - nbt.putBoolean("NoAI", this.isNoAi()); - } - -+ nbt.putBoolean("Bukkit.Aware", this.aware); // CraftBukkit - } - - @Override - public void readAdditionalSaveData(CompoundTag nbt) { - super.readAdditionalSaveData(nbt); -- this.setCanPickUpLoot(nbt.getBoolean("CanPickUpLoot")); -- this.persistenceRequired = nbt.getBoolean("PersistenceRequired"); -+ // CraftBukkit start - If looting or persistence is false only use it if it was set after we started using it -+ if (nbt.contains("CanPickUpLoot", 99)) { -+ boolean data = nbt.getBoolean("CanPickUpLoot"); -+ if (isLevelAtLeast(nbt, 1) || data) { -+ this.setCanPickUpLoot(data); -+ } -+ } -+ -+ boolean data = nbt.getBoolean("PersistenceRequired"); -+ if (isLevelAtLeast(nbt, 1) || data) { -+ this.persistenceRequired = data; -+ } -+ // CraftBukkit end - ListTag nbttaglist; - CompoundTag nbttagcompound1; - int i; -@@ -540,13 +609,18 @@ - this.readLeashData(nbt); - this.setLeftHanded(nbt.getBoolean("LeftHanded")); - if (nbt.contains("DeathLootTable", 8)) { -- this.lootTable = Optional.of(ResourceKey.create(Registries.LOOT_TABLE, ResourceLocation.parse(nbt.getString("DeathLootTable")))); -+ this.lootTable = Optional.ofNullable(ResourceLocation.tryParse(nbt.getString("DeathLootTable"))).map((rs) -> ResourceKey.create(Registries.LOOT_TABLE, rs)); // Paper - Validate ResourceLocation - } else { - this.lootTable = Optional.empty(); - } - - this.lootTableSeed = nbt.getLong("DeathLootTableSeed"); - this.setNoAi(nbt.getBoolean("NoAI")); -+ // CraftBukkit start -+ if (nbt.contains("Bukkit.Aware")) { -+ this.aware = nbt.getBoolean("Bukkit.Aware"); -+ } -+ // CraftBukkit end - } - - @Override -@@ -608,6 +682,11 @@ - ItemEntity entityitem = (ItemEntity) iterator.next(); - - if (!entityitem.isRemoved() && !entityitem.getItem().isEmpty() && !entityitem.hasPickUpDelay() && this.wantsToPickUp(worldserver, entityitem.getItem())) { -+ // Paper start - Item#canEntityPickup -+ if (!entityitem.canMobPickup) { -+ continue; -+ } -+ // Paper end - Item#canEntityPickup - this.pickUpItem(worldserver, entityitem); - } - } -@@ -623,23 +702,29 @@ - - protected void pickUpItem(ServerLevel world, ItemEntity itemEntity) { - ItemStack itemstack = itemEntity.getItem(); -- ItemStack itemstack1 = this.equipItemIfPossible(world, itemstack.copy()); -+ ItemStack itemstack1 = this.equipItemIfPossible(world, itemstack.copy(), itemEntity); // CraftBukkit - add item - - if (!itemstack1.isEmpty()) { - this.onItemPickup(itemEntity); - this.take(itemEntity, itemstack1.getCount()); - itemstack.shrink(itemstack1.getCount()); - if (itemstack.isEmpty()) { -- itemEntity.discard(); -+ itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause - } - } - - } - - public ItemStack equipItemIfPossible(ServerLevel world, ItemStack stack) { -- EquipmentSlot enumitemslot = this.getEquipmentSlotForItem(stack); -+ // CraftBukkit start - add item -+ return this.equipItemIfPossible(world, stack, null); -+ } -+ -+ public ItemStack equipItemIfPossible(ServerLevel worldserver, ItemStack itemstack, ItemEntity entityitem) { -+ // CraftBukkit end -+ EquipmentSlot enumitemslot = this.getEquipmentSlotForItem(itemstack); - ItemStack itemstack1 = this.getItemBySlot(enumitemslot); -- boolean flag = this.canReplaceCurrentItem(stack, itemstack1, enumitemslot); -+ boolean flag = this.canReplaceCurrentItem(itemstack, itemstack1, enumitemslot); - - if (enumitemslot.isArmor() && !flag) { - enumitemslot = EquipmentSlot.MAINHAND; -@@ -647,14 +732,22 @@ - flag = itemstack1.isEmpty(); - } - -- if (flag && this.canHoldItem(stack)) { -+ // CraftBukkit start -+ boolean canPickup = flag && this.canHoldItem(itemstack); -+ if (entityitem != null) { -+ canPickup = !org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, entityitem, 0, !canPickup).isCancelled(); -+ } -+ if (canPickup) { -+ // CraftBukkit end - double d0 = (double) this.getEquipmentDropChance(enumitemslot); - - if (!itemstack1.isEmpty() && (double) Math.max(this.random.nextFloat() - 0.1F, 0.0F) < d0) { -- this.spawnAtLocation(world, itemstack1); -+ this.forceDrops = true; // CraftBukkit -+ this.spawnAtLocation(worldserver, itemstack1); -+ this.forceDrops = false; // CraftBukkit - } - -- ItemStack itemstack2 = enumitemslot.limit(stack); -+ ItemStack itemstack2 = enumitemslot.limit(itemstack); - - this.setItemSlotAndDropWhenKilled(enumitemslot, itemstack2); - return itemstack2; -@@ -768,25 +861,29 @@ - @Override - public void checkDespawn() { - if (this.level().getDifficulty() == Difficulty.PEACEFUL && this.shouldDespawnInPeaceful()) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - } else if (!this.isPersistenceRequired() && !this.requiresCustomPersistence()) { -- Player entityhuman = this.level().getNearestPlayer(this, -1.0D); -+ Player entityhuman = this.level().findNearbyPlayer(this, -1.0D, EntitySelector.PLAYER_AFFECTS_SPAWNING); // Paper - Affects Spawning API - - if (entityhuman != null) { -- double d0 = entityhuman.distanceToSqr((Entity) this); -- int i = this.getType().getCategory().getDespawnDistance(); -- int j = i * i; -- -- if (d0 > (double) j && this.removeWhenFarAway(d0)) { -- this.discard(); -+ // Paper start - Configurable despawn distances -+ final io.papermc.paper.configuration.WorldConfiguration.Entities.Spawning.DespawnRangePair despawnRangePair = this.level().paperConfig().entities.spawning.despawnRanges.get(this.getType().getCategory()); -+ final io.papermc.paper.configuration.type.DespawnRange.Shape shape = this.level().paperConfig().entities.spawning.despawnRangeShape; -+ final double dy = Math.abs(entityhuman.getY() - this.getY()); -+ final double dySqr = Math.pow(dy, 2); -+ final double dxSqr = Math.pow(entityhuman.getX() - this.getX(), 2); -+ final double dzSqr = Math.pow(entityhuman.getZ() - this.getZ(), 2); -+ final double distanceSquared = dxSqr + dzSqr + dySqr; -+ // Despawn if hard/soft limit is exceeded -+ if (despawnRangePair.hard().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy) && this.removeWhenFarAway(distanceSquared)) { -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - } -- -- int k = this.getType().getCategory().getNoDespawnDistance(); -- int l = k * k; -- -- if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && d0 > (double) l && this.removeWhenFarAway(d0)) { -- this.discard(); -- } else if (d0 < (double) l) { -+ if (despawnRangePair.soft().shouldDespawn(shape, dxSqr, dySqr, dzSqr, dy)) { -+ if (this.noActionTime > 600 && this.random.nextInt(800) == 0 && this.removeWhenFarAway(distanceSquared)) { -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause -+ } -+ } else { -+ // Paper end - Configurable despawn distances - this.noActionTime = 0; - } - } -@@ -799,6 +896,15 @@ - @Override - protected final void serverAiStep() { - ++this.noActionTime; -+ // Paper start - Allow nerfed mobs to jump and float -+ if (!this.aware) { -+ if (goalFloat != null) { -+ if (goalFloat.canUse()) goalFloat.tick(); -+ this.getJumpControl().tick(); -+ } -+ return; -+ } -+ // Paper end - Allow nerfed mobs to jump and float - ProfilerFiller gameprofilerfiller = Profiler.get(); - - gameprofilerfiller.push("sensing"); -@@ -994,23 +1100,36 @@ - - @Override - public void setItemSlot(EquipmentSlot slot, ItemStack stack) { -+ // Paper start - Fix silent equipment change -+ setItemSlot(slot, stack, false); -+ } -+ -+ @Override -+ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) { -+ // Paper end - Fix silent equipment change - this.verifyEquippedItem(stack); - switch (slot.getType()) { - case HAND: -- this.onEquipItem(slot, (ItemStack) this.handItems.set(slot.getIndex(), stack), stack); -+ this.onEquipItem(slot, (ItemStack) this.handItems.set(slot.getIndex(), stack), stack, silent); // Paper - Fix silent equipment change - break; - case HUMANOID_ARMOR: -- this.onEquipItem(slot, (ItemStack) this.armorItems.set(slot.getIndex(), stack), stack); -+ this.onEquipItem(slot, (ItemStack) this.armorItems.set(slot.getIndex(), stack), stack, silent); // Paper - Fix silent equipment change - break; - case ANIMAL_ARMOR: - ItemStack itemstack1 = this.bodyArmorItem; - - this.bodyArmorItem = stack; -- this.onEquipItem(slot, itemstack1, stack); -+ this.onEquipItem(slot, itemstack1, stack, silent); // Paper - Fix silent equipment change - } - - } - -+ // Paper start -+ protected boolean shouldSkipLoot(EquipmentSlot slot) { // method to avoid to fallback into the global mob loot logic (i.e fox) -+ return false; -+ } -+ // Paper end -+ - @Override - protected void dropCustomDeathLoot(ServerLevel world, DamageSource source, boolean causedByPlayer) { - super.dropCustomDeathLoot(world, source, causedByPlayer); -@@ -1018,6 +1137,7 @@ - - while (iterator.hasNext()) { - EquipmentSlot enumitemslot = (EquipmentSlot) iterator.next(); -+ if (this.shouldSkipLoot(enumitemslot)) continue; // Paper - ItemStack itemstack = this.getItemBySlot(enumitemslot); - float f = this.getEquipmentDropChance(enumitemslot); - -@@ -1042,7 +1162,13 @@ - } - - this.spawnAtLocation(world, itemstack); -+ if (this.clearEquipmentSlots) { // Paper - this.setItemSlot(enumitemslot, ItemStack.EMPTY); -+ // Paper start -+ } else { -+ this.clearedEquipmentSlots.add(enumitemslot); -+ } -+ // Paper end - } - } - } -@@ -1338,7 +1464,7 @@ - if (itemstack.getItem() instanceof SpawnEggItem) { - if (this.level() instanceof ServerLevel) { - SpawnEggItem itemmonsteregg = (SpawnEggItem) itemstack.getItem(); -- Optional<Mob> optional = itemmonsteregg.spawnOffspringFromSpawnEgg(player, this, this.getType(), (ServerLevel) this.level(), this.position(), itemstack); -+ Optional<Mob> optional = itemmonsteregg.spawnOffspringFromSpawnEgg(player, this, (EntityType<? extends Mob>) this.getType(), (ServerLevel) this.level(), this.position(), itemstack); // CraftBukkit - decompile error - - optional.ifPresent((entityinsentient) -> { - this.onOffspringSpawnedFromEgg(player, entityinsentient); -@@ -1389,28 +1515,51 @@ - return this.restrictRadius != -1.0F; - } - -+ // CraftBukkit start - @Nullable - public <T extends Mob> T convertTo(EntityType<T> entityType, ConversionParams context, EntitySpawnReason reason, ConversionParams.AfterConversion<T> finalizer) { -+ return this.convertTo(entityType, context, reason, finalizer, EntityTransformEvent.TransformReason.UNKNOWN, CreatureSpawnEvent.SpawnReason.DEFAULT); -+ } -+ -+ @Nullable -+ public <T extends Mob> T convertTo(EntityType<T> entitytypes, ConversionParams conversionparams, EntitySpawnReason entityspawnreason, ConversionParams.AfterConversion<T> conversionparams_a, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason spawnReason) { -+ // Paper start - entity zap event - allow cancellation of conversion post creation -+ return this.convertTo(entitytypes, conversionparams, entityspawnreason, e -> { conversionparams_a.finalizeConversion(e); return true; }, transformReason, spawnReason); -+ } -+ @Nullable -+ public <T extends Mob> T convertTo(EntityType<T> entitytypes, ConversionParams conversionparams, EntitySpawnReason entityspawnreason, ConversionParams.CancellingAfterConversion<T> conversionparams_a, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason spawnReason) { -+ // Paper end - entity zap event - allow cancellation of conversion post creation -+ // CraftBukkit end - if (this.isRemoved()) { - return null; - } else { -- T t0 = (Mob) entityType.create(this.level(), reason); -+ T t0 = entitytypes.create(this.level(), EntitySpawnReason.CONVERSION); // CraftBukkit - decompile error - - if (t0 == null) { - return null; - } else { -- context.type().convert(this, t0, context); -- finalizer.finalizeConversion(t0); -+ conversionparams.type().convert(this, t0, conversionparams); -+ if (!conversionparams_a.finalizeConversionOrCancel(t0)) return null; // Paper - entity zap event - return null if conversion was cancelled - Level world = this.level(); - -+ // CraftBukkit start -+ if (transformReason == null) { -+ // Special handling for slime split and pig lightning -+ return t0; -+ } -+ -+ if (CraftEventFactory.callEntityTransformEvent(this, t0, transformReason).isCancelled()) { -+ return null; -+ } -+ // CraftBukkit end - if (world instanceof ServerLevel) { - ServerLevel worldserver = (ServerLevel) world; - -- worldserver.addFreshEntity(t0); -+ worldserver.addFreshEntity(t0, spawnReason); // CraftBukkit - } - -- if (context.type().shouldDiscardAfterConversion()) { -- this.discard(); -+ if (conversionparams.type().shouldDiscardAfterConversion()) { -+ this.discard(EntityRemoveEvent.Cause.TRANSFORMATION); // CraftBukkit - add Bukkit remove cause - } - - return t0; -@@ -1420,10 +1569,22 @@ - - @Nullable - public <T extends Mob> T convertTo(EntityType<T> entityType, ConversionParams context, ConversionParams.AfterConversion<T> finalizer) { -- return this.convertTo(entityType, context, EntitySpawnReason.CONVERSION, finalizer); -+ // CraftBukkit start -+ return this.convertTo(entityType, context, finalizer, EntityTransformEvent.TransformReason.UNKNOWN, CreatureSpawnEvent.SpawnReason.DEFAULT); - } - - @Nullable -+ public <T extends Mob> T convertTo(EntityType<T> entitytypes, ConversionParams conversionparams, ConversionParams.AfterConversion<T> conversionparams_a, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason spawnReason) { -+ // Paper start - entity zap event - allow cancellation of conversion post creation -+ return this.convertTo(entitytypes, conversionparams, e -> { conversionparams_a.finalizeConversion(e); return true; }, transformReason, spawnReason); -+ } -+ public <T extends Mob> T convertTo(EntityType<T> entitytypes, ConversionParams conversionparams, ConversionParams.CancellingAfterConversion<T> conversionparams_a, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason spawnReason) { -+ // Paper start - entity zap event - allow cancellation of conversion post creation -+ return this.convertTo(entitytypes, conversionparams, EntitySpawnReason.CONVERSION, conversionparams_a, transformReason, spawnReason); -+ // CraftBukkit end -+ } -+ -+ @Nullable - @Override - public Leashable.LeashData getLeashData() { - return this.leashData; -@@ -1458,7 +1619,15 @@ - boolean flag1 = super.startRiding(entity, force); - - if (flag1 && this.isLeashed()) { -- this.dropLeash(); -+ // Paper start - Expand EntityUnleashEvent -+ EntityUnleashEvent event = new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.UNKNOWN, true); -+ if (!event.callEvent()) { return flag1; } -+ if (event.isDropLeash()) { -+ this.dropLeash(); -+ } else { -+ this.removeLeash(); -+ } -+ // Paper end - Expand EntityUnleashEvent - } - - return flag1; -@@ -1542,7 +1711,7 @@ - - if (f1 > 0.0F && target instanceof LivingEntity) { - entityliving = (LivingEntity) target; -- entityliving.knockback((double) (f1 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F))); -+ entityliving.knockback((double) (f1 * 0.5F), (double) Mth.sin(this.getYRot() * 0.017453292F), (double) (-Mth.cos(this.getYRot() * 0.017453292F)), this, io.papermc.paper.event.entity.EntityKnockbackEvent.Cause.ENTITY_ATTACK); // CraftBukkit // Paper - knockback events - this.setDeltaMovement(this.getDeltaMovement().multiply(0.6D, 1.0D, 0.6D)); - } - diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/NeutralMob.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/NeutralMob.java.patch deleted file mode 100644 index 2088822118..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/NeutralMob.java.patch +++ /dev/null @@ -1,86 +0,0 @@ ---- a/net/minecraft/world/entity/NeutralMob.java -+++ b/net/minecraft/world/entity/NeutralMob.java -@@ -8,6 +8,9 @@ - import net.minecraft.world.entity.player.Player; - import net.minecraft.world.level.GameRules; - import net.minecraft.world.level.Level; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityTargetEvent; -+// CraftBukkit end - - public interface NeutralMob { - -@@ -42,24 +45,11 @@ - UUID uuid = nbt.getUUID("AngryAt"); - - this.setPersistentAngerTarget(uuid); -- Entity entity = ((ServerLevel) world).getEntity(uuid); -- -- if (entity != null) { -- if (entity instanceof Mob) { -- Mob entityinsentient = (Mob) entity; -- -- this.setTarget(entityinsentient); -- this.setLastHurtByMob(entityinsentient); -- } -- -- if (entity instanceof Player) { -- Player entityhuman = (Player) entity; -- -- this.setTarget(entityhuman); -- this.setLastHurtByPlayer(entityhuman); -- } -- -- } -+ // Paper - Prevent entity loading causing async lookups; Moved diff to separate method -+ // If this entity already survived its first tick, e.g. is loaded and ticked in sync, actively -+ // tick the initial persistent anger. -+ // If not, let the first tick on the baseTick call the method later down the line. -+ if (this instanceof Entity entity && !entity.firstTick) this.tickInitialPersistentAnger(world); - } - } - } -@@ -114,7 +104,7 @@ - default void stopBeingAngry() { - this.setLastHurtByMob((LivingEntity) null); - this.setPersistentAngerTarget((UUID) null); -- this.setTarget((LivingEntity) null); -+ this.setTarget((LivingEntity) null, org.bukkit.event.entity.EntityTargetEvent.TargetReason.FORGOT_TARGET, true); // CraftBukkit - this.setRemainingPersistentAngerTime(0); - } - -@@ -127,8 +117,34 @@ - - void setTarget(@Nullable LivingEntity target); - -+ boolean setTarget(@Nullable LivingEntity entityliving, org.bukkit.event.entity.EntityTargetEvent.TargetReason reason, boolean fireEvent); // CraftBukkit -+ - boolean canAttack(LivingEntity target); - - @Nullable - LivingEntity getTarget(); -+ -+ // Paper start - Prevent entity loading causing async lookups -+ // Update last hurt when ticking -+ default void tickInitialPersistentAnger(Level level) { -+ UUID target = getPersistentAngerTarget(); -+ if (target == null) { -+ return; -+ } -+ -+ Entity entity = ((ServerLevel) level).getEntity(target); -+ -+ if (entity != null) { -+ if (entity instanceof Mob mob) { -+ this.setTarget(mob, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit -+ this.setLastHurtByMob(mob); -+ } -+ -+ if (entity instanceof Player player) { -+ this.setTarget(player, EntityTargetEvent.TargetReason.UNKNOWN, false); // CraftBukkit -+ this.setLastHurtByPlayer(player); -+ } -+ } -+ } -+ // Paper end - Prevent entity loading causing async lookups - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/PathfinderMob.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/PathfinderMob.java.patch deleted file mode 100644 index 24a880fc47..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/PathfinderMob.java.patch +++ /dev/null @@ -1,12 +0,0 @@ ---- a/net/minecraft/world/entity/PathfinderMob.java -+++ b/net/minecraft/world/entity/PathfinderMob.java -@@ -10,6 +10,9 @@ - import net.minecraft.world.level.LevelAccessor; - import net.minecraft.world.level.LevelReader; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityUnleashEvent; -+// CraftBukkit end - - public abstract class PathfinderMob extends Mob { - diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/TamableAnimal.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/TamableAnimal.java.patch deleted file mode 100644 index ae8be7d5d0..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/TamableAnimal.java.patch +++ /dev/null @@ -1,85 +0,0 @@ ---- a/net/minecraft/world/entity/TamableAnimal.java -+++ b/net/minecraft/world/entity/TamableAnimal.java -@@ -27,6 +27,11 @@ - import net.minecraft.world.level.pathfinder.PathType; - import net.minecraft.world.level.pathfinder.WalkNodeEvaluator; - import net.minecraft.world.scores.PlayerTeam; -+// CraftBukkit start -+import org.bukkit.Location; -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+import org.bukkit.event.entity.EntityTeleportEvent; -+// CraftBukkit end - - public abstract class TamableAnimal extends Animal implements OwnableEntity { - -@@ -85,7 +90,7 @@ - } - - this.orderedToSit = nbt.getBoolean("Sitting"); -- this.setInSittingPose(this.orderedToSit); -+ this.setInSittingPose(this.orderedToSit, false); // Paper - Add EntityToggleSitEvent - } - - @Override -@@ -96,8 +101,16 @@ - @Override - public boolean handleLeashAtDistance(Entity leashHolder, float distance) { - if (this.isInSittingPose()) { -- if (distance > 10.0F) { -- this.dropLeash(); -+ if (distance > (float) this.level().paperConfig().misc.maxLeashDistance.or(Leashable.LEASH_TOO_FAR_DIST)) { // Paper - Configurable max leash distance -+ // Paper start - Expand EntityUnleashEvent -+ org.bukkit.event.entity.EntityUnleashEvent event = new org.bukkit.event.entity.EntityUnleashEvent(this.getBukkitEntity(), org.bukkit.event.entity.EntityUnleashEvent.UnleashReason.DISTANCE, true); -+ if (!event.callEvent()) return false; -+ if (event.isDropLeash()) { -+ this.dropLeash(); -+ } else { -+ this.removeLeash(); -+ } -+ // Paper end - Expand EntityUnleashEvent - } - - return false; -@@ -161,6 +174,12 @@ - } - - public void setInSittingPose(boolean inSittingPose) { -+ // Paper start - Add EntityToggleSitEvent -+ this.setInSittingPose(inSittingPose, true); -+ } -+ public void setInSittingPose(boolean inSittingPose, boolean callEvent) { -+ if (callEvent && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), inSittingPose).callEvent()) return; -+ // Paper end - Add EntityToggleSitEvent - byte b0 = (Byte) this.entityData.get(TamableAnimal.DATA_FLAGS_ID); - - if (inSittingPose) { -@@ -244,7 +263,12 @@ - if (entityliving instanceof ServerPlayer) { - ServerPlayer entityplayer = (ServerPlayer) entityliving; - -- entityplayer.sendSystemMessage(this.getCombatTracker().getDeathMessage()); -+ // Paper start - Add TameableDeathMessageEvent -+ io.papermc.paper.event.entity.TameableDeathMessageEvent event = new io.papermc.paper.event.entity.TameableDeathMessageEvent((org.bukkit.entity.Tameable) getBukkitEntity(), io.papermc.paper.adventure.PaperAdventure.asAdventure(this.getCombatTracker().getDeathMessage())); -+ if (event.callEvent()) { -+ entityplayer.sendSystemMessage(io.papermc.paper.adventure.PaperAdventure.asVanilla(event.deathMessage())); -+ } -+ // Paper end - Add TameableDeathMessageEvent - } - } - } -@@ -295,7 +319,14 @@ - if (!this.canTeleportTo(new BlockPos(x, y, z))) { - return false; - } else { -- this.moveTo((double) x + 0.5D, (double) y, (double) z + 0.5D, this.getYRot(), this.getXRot()); -+ // CraftBukkit start -+ EntityTeleportEvent event = CraftEventFactory.callEntityTeleportEvent(this, (double) x + 0.5D, (double) y, (double) z + 0.5D); -+ if (event.isCancelled() || event.getTo() == null) { // Paper - prevent NP on null event to location -+ return false; -+ } -+ Location to = event.getTo(); -+ this.moveTo(to.getX(), to.getY(), to.getZ(), to.getYaw(), to.getPitch()); -+ // CraftBukkit end - this.navigation.stop(); - return true; - }