diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch new file mode 100644 index 0000000000..35bee18fdb --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch @@ -0,0 +1,79 @@ +--- a/net/minecraft/world/entity/monster/AbstractSkeleton.java ++++ b/net/minecraft/world/entity/monster/AbstractSkeleton.java +@@ -64,6 +_,11 @@ + AbstractSkeleton.this.setAggressive(true); + } + }; ++ // Paper start - shouldBurnInDay API ++ private boolean shouldBurnInDay = true; ++ public boolean shouldBurnInDay() { return shouldBurnInDay; } ++ public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } ++ // Paper end - shouldBurnInDay API + + protected AbstractSkeleton(EntityType entityType, Level level) { + super(entityType, level); +@@ -97,7 +_,7 @@ + + @Override + public void aiStep() { +- boolean isSunBurnTick = this.isSunBurnTick(); ++ boolean isSunBurnTick = this.shouldBurnInDay && this.isSunBurnTick(); // Paper - shouldBurnInDay API + if (isSunBurnTick) { + ItemStack itemBySlot = this.getItemBySlot(EquipmentSlot.HEAD); + if (!itemBySlot.isEmpty()) { +@@ -145,7 +_,7 @@ + this.populateDefaultEquipmentSlots(random, difficulty); + this.populateDefaultEquipmentEnchantments(level, random, difficulty); + this.reassessWeaponGoal(); +- this.setCanPickUpLoot(random.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); ++ this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || random.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper - Add world settings for mobs picking up loot + if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { + LocalDate localDate = LocalDate.now(); + int i = localDate.get(ChronoField.DAY_OF_MONTH); +@@ -196,9 +_,19 @@ + double d2 = target.getZ() - this.getZ(); + double squareRoot = Math.sqrt(d * d + d2 * d2); + if (this.level() instanceof ServerLevel serverLevel) { ++ // CraftBukkit start ++ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), arrow.getPickupItem(), arrow, net.minecraft.world.InteractionHand.MAIN_HAND, 0.8F, true); // Paper - improve entity shhot bow event - add arrow stack to event ++ if (event.isCancelled()) { ++ event.getProjectile().remove(); ++ return; ++ } ++ ++ if (event.getProjectile() == arrow.getBukkitEntity()) { ++ // CraftBukkit end + Projectile.spawnProjectileUsingShoot( + arrow, serverLevel, projectile, d, d1 + squareRoot * 0.2F, d2, 1.6F, 14 - serverLevel.getDifficulty().getId() * 4 + ); ++ } // CraftBukkit + } + + this.playSound(SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (this.getRandom().nextFloat() * 0.4F + 0.8F)); +@@ -222,11 +_,23 @@ + public void readAdditionalSaveData(CompoundTag compound) { + super.readAdditionalSaveData(compound); + this.reassessWeaponGoal(); +- } ++ // Paper start - shouldBurnInDay API ++ if (compound.contains("Paper.ShouldBurnInDay")) { ++ this.shouldBurnInDay = compound.getBoolean("Paper.ShouldBurnInDay"); ++ } ++ // Paper end - shouldBurnInDay API ++ } ++ // Paper start - shouldBurnInDay API ++ @Override ++ public void addAdditionalSaveData(final net.minecraft.nbt.CompoundTag nbt) { ++ super.addAdditionalSaveData(nbt); ++ nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); ++ } ++ // Paper end - shouldBurnInDay API + + @Override +- public void setItemSlot(EquipmentSlot slot, ItemStack stack) { +- super.setItemSlot(slot, stack); ++ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) { // Paper - Fix silent equipment change ++ super.setItemSlot(slot, stack, silent); // Paper - Fix silent equipment change + if (!this.level().isClientSide) { + this.reassessWeaponGoal(); + } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Bogged.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Bogged.java.patch similarity index 51% rename from paper-server/patches/unapplied/net/minecraft/world/entity/monster/Bogged.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/monster/Bogged.java.patch index 1cd68614bd..a9624e7f90 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Bogged.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Bogged.java.patch @@ -1,22 +1,14 @@ --- a/net/minecraft/world/entity/monster/Bogged.java +++ b/net/minecraft/world/entity/monster/Bogged.java -@@ -27,6 +27,7 @@ - import net.minecraft.world.level.Level; - import net.minecraft.world.level.gameevent.GameEvent; - import net.minecraft.world.level.storage.loot.BuiltInLootTables; -+import org.bukkit.craftbukkit.event.CraftEventFactory; - - public class Bogged extends AbstractSkeleton implements Shearable { - -@@ -79,7 +80,20 @@ - if (world instanceof ServerLevel) { - ServerLevel worldserver = (ServerLevel) world; - -- this.shear(worldserver, SoundSource.PLAYERS, itemstack); +@@ -72,7 +_,20 @@ + ItemStack itemInHand = player.getItemInHand(hand); + if (itemInHand.is(Items.SHEARS) && this.readyForShearing()) { + if (this.level() instanceof ServerLevel serverLevel) { +- this.shear(serverLevel, SoundSource.PLAYERS, itemInHand); + // CraftBukkit start + // Paper start - custom shear drops -+ java.util.List drops = this.generateDefaultDrops(worldserver, itemstack); -+ org.bukkit.event.player.PlayerShearEntityEvent event = CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemstack, hand, drops); ++ java.util.List drops = this.generateDefaultDrops(serverLevel, itemInHand); ++ org.bukkit.event.player.PlayerShearEntityEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.handlePlayerShearEntityEvent(player, this, itemInHand, hand, drops); + if (event != null) { + if (event.isCancelled()) { + // this.getEntityData().markDirty(Bogged.DATA_SHEARED); // CraftBukkit - mark dirty to restore sheared state to clients // Paper - no longer needed @@ -26,16 +18,16 @@ + // Paper end - custom shear drops + } + // CraftBukkit end -+ this.shear(worldserver, SoundSource.PLAYERS, itemstack, drops); // Paper - custom shear drops ++ this.shear(serverLevel, SoundSource.PLAYERS, itemInHand, drops); // Paper - custom shear drops this.gameEvent(GameEvent.SHEAR, player); - itemstack.hurtAndBreak(1, player, getSlotForHand(hand)); + itemInHand.hurtAndBreak(1, player, getSlotForHand(hand)); } -@@ -133,15 +147,36 @@ +@@ -125,15 +_,34 @@ @Override - public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears) { + public void shear(ServerLevel level, SoundSource soundSource, ItemStack shears) { + // Paper start - custom shear drops -+ this.shear(world, shearedSoundCategory, shears, this.generateDefaultDrops(world, shears)); ++ this.shear(level, soundSource, shears, this.generateDefaultDrops(level, shears)); + } + + @Override @@ -48,25 +40,24 @@ + } + + @Override -+ public void shear(ServerLevel world, SoundSource shearedSoundCategory, ItemStack shears, java.util.List drops) { ++ public void shear(ServerLevel level, SoundSource soundSource, ItemStack shears, java.util.List drops) { + // Paper end - custom shear drops - world.playSound((Player) null, (Entity) this, SoundEvents.BOGGED_SHEAR, shearedSoundCategory, 1.0F, 1.0F); -- this.spawnShearedMushrooms(world, shears); -+ this.spawnShearedMushrooms(world, shears, drops); // Paper - custom shear drops + level.playSound(null, this, SoundEvents.BOGGED_SHEAR, soundSource, 1.0F, 1.0F); + this.spawnShearedMushrooms(level, shears); this.setSheared(true); } -- private void spawnShearedMushrooms(ServerLevel world, ItemStack shears) { -- this.dropFromShearingLootTable(world, BuiltInLootTables.BOGGED_SHEAR, shears, (worldserver1, itemstack1) -> { +- private void spawnShearedMushrooms(ServerLevel level, ItemStack stack) { +- this.dropFromShearingLootTable( +- level, BuiltInLootTables.BOGGED_SHEAR, stack, (serverLevel, itemStack) -> this.spawnAtLocation(serverLevel, itemStack, this.getBbHeight()) +- ); + // Paper start - custom shear drops + private void spawnShearedMushrooms(ServerLevel world, ItemStack shears, java.util.List drops) { + final ServerLevel worldserver1 = world; // Named for lambda consumption + this.forceDrops = true; // Paper - Add missing forceDrop toggles -+ drops.forEach(itemstack1 -> { -+ // Paper end - custom shear drops - this.spawnAtLocation(worldserver1, itemstack1, this.getBbHeight()); - }); ++ drops.forEach(itemstack1 -> this.spawnAtLocation(world, shears, this.getBbHeight())); + this.forceDrops = false; // Paper - Add missing forceDrop toggles ++ // Paper end - custom shear drops } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/CaveSpider.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/CaveSpider.java.patch new file mode 100644 index 0000000000..2b7ce5164e --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/CaveSpider.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/CaveSpider.java ++++ b/net/minecraft/world/entity/monster/CaveSpider.java +@@ -38,7 +_,7 @@ + } + + if (i > 0) { +- ((LivingEntity)source).addEffect(new MobEffectInstance(MobEffects.POISON, i * 20, 0), this); ++ ((LivingEntity)source).addEffect(new MobEffectInstance(MobEffects.POISON, i * 20, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + } + } + diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Creeper.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Creeper.java.patch new file mode 100644 index 0000000000..30d6bab42b --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Creeper.java.patch @@ -0,0 +1,114 @@ +--- a/net/minecraft/world/entity/monster/Creeper.java ++++ b/net/minecraft/world/entity/monster/Creeper.java +@@ -49,6 +_,7 @@ + public int maxSwell = 30; + public int explosionRadius = 3; + private int droppedSkulls; ++ public Entity entityIgniter; // CraftBukkit + + public Creeper(EntityType entityType, Level level) { + super(entityType, level); +@@ -121,7 +_,7 @@ + } + + if (compound.getBoolean("ignited")) { +- this.ignite(); ++ this.entityData.set(Creeper.DATA_IS_IGNITED, true); // Paper - set directly to avoid firing event + } + } + +@@ -204,8 +_,19 @@ + @Override + public void thunderHit(ServerLevel level, LightningBolt lightning) { + super.thunderHit(level, lightning); ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callCreeperPowerEvent(this, lightning, org.bukkit.event.entity.CreeperPowerEvent.PowerCause.LIGHTNING).isCancelled()) { ++ return; ++ } ++ // CraftBukkit end + this.entityData.set(DATA_IS_POWERED, true); + } ++ // CraftBukkit start ++ public void setPowered(boolean powered) { ++ this.entityData.set(Creeper.DATA_IS_POWERED, powered); ++ } ++ // CraftBukkit end ++ + + @Override + protected InteractionResult mobInteract(Player player, InteractionHand hand) { +@@ -215,8 +_,9 @@ + this.level() + .playSound(player, this.getX(), this.getY(), this.getZ(), soundEvent, this.getSoundSource(), 1.0F, this.random.nextFloat() * 0.4F + 0.8F); + if (!this.level().isClientSide) { ++ this.entityIgniter = player; // CraftBukkit + this.ignite(); +- if (!itemInHand.isDamageableItem()) { ++ if (itemInHand.getMaxDamage() == 0) { // CraftBukkit - fix MC-264285: unbreakable flint and steels are completely consumed when igniting a creeper + itemInHand.shrink(1); + } else { + itemInHand.hurtAndBreak(1, player, getSlotForHand(hand)); +@@ -232,18 +_,29 @@ + public void explodeCreeper() { + if (this.level() instanceof ServerLevel serverLevel) { + float f = this.isPowered() ? 2.0F : 1.0F; ++ // CraftBukkit start ++ org.bukkit.event.entity.ExplosionPrimeEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callExplosionPrimeEvent(this, this.explosionRadius * f, false); ++ if (!event.isCancelled()) { ++ // CraftBukkit end + this.dead = true; +- serverLevel.explode(this, this.getX(), this.getY(), this.getZ(), this.explosionRadius * f, Level.ExplosionInteraction.MOB); ++ serverLevel.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this) + this.spawnLingeringCloud(); + this.triggerOnDeathMobEffects(serverLevel, Entity.RemovalReason.KILLED); +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause ++ // CraftBukkit start ++ } else { ++ this.swell = 0; ++ this.entityData.set(DATA_IS_IGNITED, Boolean.valueOf(false)); // Paper ++ } ++ // CraftBukkit end + } + } + + private void spawnLingeringCloud() { + Collection activeEffects = this.getActiveEffects(); +- if (!activeEffects.isEmpty()) { ++ if (!activeEffects.isEmpty() && !this.level().paperConfig().entities.behavior.disableCreeperLingeringEffect) { // Paper - Option to disable creeper lingering effect + AreaEffectCloud areaEffectCloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); ++ areaEffectCloud.setOwner(this); // CraftBukkit + areaEffectCloud.setRadius(2.5F); + areaEffectCloud.setRadiusOnUse(-0.5F); + areaEffectCloud.setWaitTime(10); +@@ -254,16 +_,26 @@ + areaEffectCloud.addEffect(new MobEffectInstance(mobEffectInstance)); + } + +- this.level().addFreshEntity(areaEffectCloud); +- } +- } ++ this.level().addFreshEntity(areaEffectCloud, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.EXPLOSION); // CraftBukkit ++ } ++ } ++ // Paper start - CreeperIgniteEvent ++ public void setIgnited(boolean ignited) { ++ if (isIgnited() != ignited) { ++ com.destroystokyo.paper.event.entity.CreeperIgniteEvent event = new com.destroystokyo.paper.event.entity.CreeperIgniteEvent((org.bukkit.entity.Creeper) getBukkitEntity(), ignited); ++ if (event.callEvent()) { ++ this.entityData.set(Creeper.DATA_IS_IGNITED, event.isIgnited()); ++ } ++ } ++ } ++ // Paper end - CreeperIgniteEvent + + public boolean isIgnited() { + return this.entityData.get(DATA_IS_IGNITED); + } + + public void ignite() { +- this.entityData.set(DATA_IS_IGNITED, true); ++ setIgnited(true); // Paper - CreeperIgniteEvent + } + + public boolean canDropMobsSkull() { diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Drowned.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Drowned.java.patch similarity index 81% rename from paper-server/patches/unapplied/net/minecraft/world/entity/monster/Drowned.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/monster/Drowned.java.patch index 938442254b..f28da7213d 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Drowned.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Drowned.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/monster/Drowned.java +++ b/net/minecraft/world/entity/monster/Drowned.java -@@ -85,7 +85,7 @@ +@@ -85,7 +_,7 @@ this.goalSelector.addGoal(7, new RandomStrollGoal(this, 1.0)); this.targetSelector.addGoal(1, new HurtByTargetGoal(this, Drowned.class).setAlertOthers(ZombifiedPiglin.class)); - this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (target, world) -> this.okTarget(target))); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, (entity, level) -> this.okTarget(entity))); - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); -+ if (this.level().spigotConfig.zombieAggressiveTowardsVillager) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); // Paper - Check drowned for villager aggression config ++ if (this.level().spigotConfig.zombieAggressiveTowardsVillager) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); // Paper - Check drowned for villager aggression config this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, Axolotl.class, true, false)); this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR)); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/ElderGuardian.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/ElderGuardian.java.patch new file mode 100644 index 0000000000..c15aa5deb4 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/ElderGuardian.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/ElderGuardian.java ++++ b/net/minecraft/world/entity/monster/ElderGuardian.java +@@ -65,7 +_,7 @@ + super.customServerAiStep(level); + if ((this.tickCount + this.getId()) % 1200 == 0) { + MobEffectInstance mobEffectInstance = new MobEffectInstance(MobEffects.DIG_SLOWDOWN, 6000, 2); +- List list = MobEffectUtil.addEffectToPlayersAround(level, this, this.position(), 50.0, mobEffectInstance, 1200); ++ List list = MobEffectUtil.addEffectToPlayersAround(level, this, this.position(), 50.0, mobEffectInstance, 1200, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK, (player) -> new io.papermc.paper.event.entity.ElderGuardianAppearanceEvent((org.bukkit.entity.ElderGuardian) this.getBukkitEntity(), player.getBukkitEntity()).callEvent()); // CraftBukkit // Paper - Add ElderGuardianAppearanceEvent + list.forEach( + serverPlayer -> serverPlayer.connection + .send(new ClientboundGameEventPacket(ClientboundGameEventPacket.GUARDIAN_ELDER_EFFECT, this.isSilent() ? 0.0F : 1.0F)) diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch new file mode 100644 index 0000000000..908813f231 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/EnderMan.java.patch @@ -0,0 +1,144 @@ +--- a/net/minecraft/world/entity/monster/EnderMan.java ++++ b/net/minecraft/world/entity/monster/EnderMan.java +@@ -116,10 +_,26 @@ + } + + @Override +- public void setTarget(@Nullable LivingEntity livingEntity) { +- super.setTarget(livingEntity); ++ public void setTarget(@Nullable LivingEntity target) { ++ // CraftBukkit start - fire event ++ this.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.UNKNOWN, true); ++ } ++ ++ // Paper start - EndermanEscapeEvent ++ private boolean tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason reason) { ++ return new com.destroystokyo.paper.event.entity.EndermanEscapeEvent((org.bukkit.craftbukkit.entity.CraftEnderman) this.getBukkitEntity(), reason).callEvent(); ++ } ++ // Paper end - EndermanEscapeEvent ++ ++ @Override ++ public boolean setTarget(LivingEntity target, org.bukkit.event.entity.EntityTargetEvent.TargetReason reason, boolean fireEvent) { ++ if (!super.setTarget(target, reason, fireEvent)) { ++ return false; ++ } ++ target = this.getTarget(); ++ // CraftBukkit end + AttributeInstance attribute = this.getAttribute(Attributes.MOVEMENT_SPEED); +- if (livingEntity == null) { ++ if (target == null) { + this.targetChangeTime = 0; + this.entityData.set(DATA_CREEPY, false); + this.entityData.set(DATA_STARED_AT, false); +@@ -131,6 +_,7 @@ + attribute.addTransientModifier(SPEED_MODIFIER_ATTACKING); + } + } ++ return true; // CraftBukkit + } + + @Override +@@ -212,6 +_,14 @@ + } + + boolean isBeingStaredBy(Player player) { ++ // Paper start - EndermanAttackPlayerEvent ++ final boolean shouldAttack = isBeingStaredBy0(player); ++ final com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent event = new com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent((org.bukkit.entity.Enderman) getBukkitEntity(), (org.bukkit.entity.Player) player.getBukkitEntity()); ++ event.setCancelled(!shouldAttack); ++ return event.callEvent(); ++ } ++ private boolean isBeingStaredBy0(Player player) { ++ // Paper end - EndermanAttackPlayerEvent + return LivingEntity.PLAYER_NOT_WEARING_DISGUISE_ITEM.test(player) && this.isLookingAtMe(player, 0.025, true, false, new double[]{this.getEyeY()}); + } + +@@ -251,7 +_,7 @@ + float lightLevelDependentMagicValue = this.getLightLevelDependentMagicValue(); + if (lightLevelDependentMagicValue > 0.5F + && level.canSeeSky(this.blockPosition()) +- && this.random.nextFloat() * 30.0F < (lightLevelDependentMagicValue - 0.4F) * 2.0F) { ++ && this.random.nextFloat() * 30.0F < (lightLevelDependentMagicValue - 0.4F) * 2.0F && this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.RUNAWAY)) { // Paper - EndermanEscapeEvent + this.setTarget(null); + this.teleport(); + } +@@ -372,11 +_,13 @@ + } else { + boolean flag1 = flag && this.hurtWithCleanWater(level, damageSource, (ThrownPotion)damageSource.getDirectEntity(), amount); + ++ if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper - EndermanEscapeEvent + for (int i = 0; i < 64; i++) { + if (this.teleport()) { + return true; + } + } ++ } // Paper - EndermanEscapeEvent + + return flag1; + } +@@ -400,6 +_,15 @@ + public void setBeingStaredAt() { + this.entityData.set(DATA_STARED_AT, true); + } ++ // Paper start ++ public void setCreepy(boolean creepy) { ++ this.entityData.set(EnderMan.DATA_CREEPY, creepy); ++ } ++ ++ public void setHasBeenStaredAt(boolean hasBeenStaredAt) { ++ this.entityData.set(EnderMan.DATA_STARED_AT, hasBeenStaredAt); ++ } ++ // Paper end + + @Override + public boolean requiresCustomPersistence() { +@@ -460,16 +_,19 @@ + int floor1 = Mth.floor(this.enderman.getY() + random.nextDouble() * 2.0); + int floor2 = Mth.floor(this.enderman.getZ() - 1.0 + random.nextDouble() * 2.0); + BlockPos blockPos = new BlockPos(floor, floor1, floor2); +- BlockState blockState = level.getBlockState(blockPos); ++ BlockState blockState = level.getBlockStateIfLoaded(blockPos); // Paper - Prevent endermen from loading chunks ++ if (blockState == null) return; // Paper - Prevent endermen from loading chunks + BlockPos blockPos1 = blockPos.below(); + BlockState blockState1 = level.getBlockState(blockPos1); + BlockState carriedBlock = this.enderman.getCarriedBlock(); + if (carriedBlock != null) { + carriedBlock = Block.updateFromNeighbourShapes(carriedBlock, this.enderman.level(), blockPos); + if (this.canPlaceBlock(level, blockPos, carriedBlock, blockState, blockState1, blockPos1)) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockPos, carriedBlock)) { // CraftBukkit - Place event + level.setBlock(blockPos, carriedBlock, 3); + level.gameEvent(GameEvent.BLOCK_PLACE, blockPos, GameEvent.Context.of(this.enderman, carriedBlock)); + this.enderman.setCarriedBlock(null); ++ } // CraftBukkit + } + } + } +@@ -567,7 +_,7 @@ + } else { + if (this.target != null && !this.enderman.isPassenger()) { + if (this.enderman.isBeingStaredBy((Player)this.target)) { +- if (this.target.distanceToSqr(this.enderman) < 16.0) { ++ if (this.target.distanceToSqr(this.enderman) < 16.0 && this.enderman.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.STARE)) { // Paper - EndermanEscapeEvent + this.enderman.teleport(); + } + +@@ -606,15 +_,18 @@ + int floor1 = Mth.floor(this.enderman.getY() + random.nextDouble() * 3.0); + int floor2 = Mth.floor(this.enderman.getZ() - 2.0 + random.nextDouble() * 4.0); + BlockPos blockPos = new BlockPos(floor, floor1, floor2); +- BlockState blockState = level.getBlockState(blockPos); ++ BlockState blockState = level.getBlockStateIfLoaded(blockPos); // Paper - Prevent endermen from loading chunks ++ if (blockState == null) return; // Paper - Prevent endermen from loading chunks + Vec3 vec3 = new Vec3(this.enderman.getBlockX() + 0.5, floor1 + 0.5, this.enderman.getBlockZ() + 0.5); + Vec3 vec31 = new Vec3(floor + 0.5, floor1 + 0.5, floor2 + 0.5); + BlockHitResult blockHitResult = level.clip(new ClipContext(vec3, vec31, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, this.enderman)); + boolean flag = blockHitResult.getBlockPos().equals(blockPos); + if (blockState.is(BlockTags.ENDERMAN_HOLDABLE) && flag) { ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockPos, blockState.getFluidState().createLegacyBlock())) { // CraftBukkit - Place event // Paper - fix wrong block state + level.removeBlock(blockPos, false); + level.gameEvent(GameEvent.BLOCK_DESTROY, blockPos, GameEvent.Context.of(this.enderman, blockState)); + this.enderman.setCarriedBlock(blockState.getBlock().defaultBlockState()); ++ } // CraftBukkit + } + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Endermite.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Endermite.java.patch new file mode 100644 index 0000000000..4677099a10 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Endermite.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/Endermite.java ++++ b/net/minecraft/world/entity/monster/Endermite.java +@@ -121,7 +_,7 @@ + } + + if (this.life >= 2400) { +- this.discard(); ++ this.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause + } + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Evoker.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Evoker.java.patch new file mode 100644 index 0000000000..5329db11c5 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Evoker.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/Evoker.java ++++ b/net/minecraft/world/entity/monster/Evoker.java +@@ -264,7 +_,7 @@ + serverLevel.getScoreboard().addPlayerToTeam(vex.getScoreboardName(), team); + } + +- serverLevel.addFreshEntityWithPassengers(vex); ++ serverLevel.addFreshEntityWithPassengers(vex, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPELL); // CraftBukkit - Add SpawnReason + serverLevel.gameEvent(GameEvent.ENTITY_PLACE, blockPos, GameEvent.Context.of(Evoker.this)); + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Ghast.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Ghast.java.patch new file mode 100644 index 0000000000..9f53b5d8a3 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Ghast.java.patch @@ -0,0 +1,23 @@ +--- a/net/minecraft/world/entity/monster/Ghast.java ++++ b/net/minecraft/world/entity/monster/Ghast.java +@@ -63,6 +_,12 @@ + return this.explosionPower; + } + ++ // Paper start ++ public void setExplosionPower(int explosionPower) { ++ this.explosionPower = explosionPower; ++ } ++ // Paper end ++ + @Override + protected boolean shouldDespawnInPeaceful() { + return true; +@@ -277,6 +_,7 @@ + } + + LargeFireball largeFireball = new LargeFireball(level, this.ghast, vec3.normalize(), this.ghast.getExplosionPower()); ++ largeFireball.bukkitYield = largeFireball.explosionPower = this.ghast.getExplosionPower(); // CraftBukkit - set bukkitYield when setting explosionpower + largeFireball.setPos(this.ghast.getX() + viewVector.x * 4.0, this.ghast.getY(0.5) + 0.5, largeFireball.getZ() + viewVector.z * 4.0); + level.addFreshEntity(largeFireball); + this.chargeTime = -40; diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Guardian.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Guardian.java.patch similarity index 60% rename from paper-server/patches/unapplied/net/minecraft/world/entity/monster/Guardian.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/monster/Guardian.java.patch index 078be667c0..5dbcc39af7 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Guardian.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Guardian.java.patch @@ -1,19 +1,19 @@ --- a/net/minecraft/world/entity/monster/Guardian.java +++ b/net/minecraft/world/entity/monster/Guardian.java -@@ -60,6 +60,7 @@ +@@ -59,6 +_,7 @@ private boolean clientSideTouchedGround; @Nullable public RandomStrollGoal randomStrollGoal; + public Guardian.GuardianAttackGoal guardianAttackGoal; // CraftBukkit - add field - public Guardian(EntityType type, Level world) { - super(type, world); -@@ -75,7 +76,7 @@ - MoveTowardsRestrictionGoal pathfindergoalmovetowardsrestriction = new MoveTowardsRestrictionGoal(this, 1.0D); - - this.randomStrollGoal = new RandomStrollGoal(this, 1.0D, 80); + public Guardian(EntityType entityType, Level level) { + super(entityType, level); +@@ -73,7 +_,7 @@ + protected void registerGoals() { + MoveTowardsRestrictionGoal moveTowardsRestrictionGoal = new MoveTowardsRestrictionGoal(this, 1.0); + this.randomStrollGoal = new RandomStrollGoal(this, 1.0, 80); - this.goalSelector.addGoal(4, new Guardian.GuardianAttackGoal(this)); + this.goalSelector.addGoal(4, this.guardianAttackGoal = new Guardian.GuardianAttackGoal(this)); // CraftBukkit - assign field - this.goalSelector.addGoal(5, pathfindergoalmovetowardsrestriction); + this.goalSelector.addGoal(5, moveTowardsRestrictionGoal); this.goalSelector.addGoal(7, this.randomStrollGoal); this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Husk.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Husk.java.patch new file mode 100644 index 0000000000..78b5ff1c16 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Husk.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/Husk.java ++++ b/net/minecraft/world/entity/monster/Husk.java +@@ -57,7 +_,7 @@ + boolean flag = super.doHurtTarget(level, source); + if (flag && this.getMainHandItem().isEmpty() && source instanceof LivingEntity) { + float effectiveDifficulty = this.level().getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty(); +- ((LivingEntity)source).addEffect(new MobEffectInstance(MobEffects.HUNGER, 140 * (int)effectiveDifficulty), this); ++ ((LivingEntity)source).addEffect(new MobEffectInstance(MobEffects.HUNGER, 140 * (int)effectiveDifficulty), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + } + + return flag; diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Illusioner.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Illusioner.java.patch similarity index 69% rename from paper-server/patches/unapplied/net/minecraft/world/entity/monster/Illusioner.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/monster/Illusioner.java.patch index b839923b98..288baed666 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Illusioner.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Illusioner.java.patch @@ -1,33 +1,26 @@ --- a/net/minecraft/world/entity/monster/Illusioner.java +++ b/net/minecraft/world/entity/monster/Illusioner.java -@@ -184,7 +184,17 @@ - Level world = this.level(); - - if (world instanceof ServerLevel worldserver) { +@@ -180,9 +_,19 @@ + double d2 = target.getZ() - this.getZ(); + double squareRoot = Math.sqrt(d * d + d2 * d2); + if (this.level() instanceof ServerLevel serverLevel) { + // Paper start - EntityShootBowEvent -+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), entityarrow.getPickupItem(), entityarrow, target.getUsedItemHand(), 0.8F, true); ++ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), mobArrow.getPickupItem(), mobArrow, target.getUsedItemHand(), 0.8F, true); + if (event.isCancelled()) { + event.getProjectile().remove(); + return; + } + -+ if (event.getProjectile() == entityarrow.getBukkitEntity()) { - Projectile.spawnProjectileUsingShoot(entityarrow, worldserver, itemstack1, d0, d1 + d3 * 0.20000000298023224D, d2, 1.6F, (float) (14 - worldserver.getDifficulty().getId() * 4)); ++ if (event.getProjectile() == mobArrow.getBukkitEntity()) { + Projectile.spawnProjectileUsingShoot( + mobArrow, serverLevel, projectile, d, d1 + squareRoot * 0.2F, d2, 1.6F, 14 - serverLevel.getDifficulty().getId() * 4 + ); + } + // Paper end - EntityShootBowEvent } this.playSound(SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (this.getRandom().nextFloat() * 0.4F + 0.8F)); -@@ -218,7 +228,7 @@ - - @Override - protected void performSpellCasting() { -- Illusioner.this.addEffect(new MobEffectInstance(MobEffects.INVISIBILITY, 1200)); -+ Illusioner.this.addEffect(new MobEffectInstance(MobEffects.INVISIBILITY, 1200), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ILLUSION); // CraftBukkit - } - - @Nullable -@@ -269,7 +279,7 @@ +@@ -229,7 +_,7 @@ @Override protected void performSpellCasting() { @@ -36,3 +29,12 @@ } @Override +@@ -261,7 +_,7 @@ + + @Override + protected void performSpellCasting() { +- Illusioner.this.addEffect(new MobEffectInstance(MobEffects.INVISIBILITY, 1200)); ++ Illusioner.this.addEffect(new MobEffectInstance(MobEffects.INVISIBILITY, 1200), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ILLUSION); // CraftBukkit + } + + @Nullable diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Monster.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Monster.java.patch similarity index 77% rename from paper-server/patches/unapplied/net/minecraft/world/entity/monster/Monster.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/monster/Monster.java.patch index bae67fa57b..842c4f8588 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Monster.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Monster.java.patch @@ -1,11 +1,11 @@ --- a/net/minecraft/world/entity/monster/Monster.java +++ b/net/minecraft/world/entity/monster/Monster.java -@@ -92,7 +92,7 @@ +@@ -92,7 +_,7 @@ return false; } else { - DimensionType dimensionType = world.dimensionType(); + DimensionType dimensionType = level.dimensionType(); - int i = dimensionType.monsterSpawnBlockLightLimit(); + int i = world.getLevel().paperConfig().entities.spawning.monsterSpawnMaxLightLevel.or(dimensionType.monsterSpawnBlockLightLimit()); // Paper - Configurable max block light for monster spawning - if (i < 15 && world.getBrightness(LightLayer.BLOCK, pos) > i) { + if (i < 15 && level.getBrightness(LightLayer.BLOCK, pos) > i) { return false; } else { diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch new file mode 100644 index 0000000000..ed1eed8680 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Phantom.java.patch @@ -0,0 +1,69 @@ +--- a/net/minecraft/world/entity/monster/Phantom.java ++++ b/net/minecraft/world/entity/monster/Phantom.java +@@ -141,7 +_,7 @@ + + @Override + public void aiStep() { +- if (this.isAlive() && this.isSunBurnTick()) { ++ if (this.isAlive() && this.shouldBurnInDay && this.isSunBurnTick()) { // Paper - shouldBurnInDay API + this.igniteForSeconds(8.0F); + } + +@@ -165,6 +_,14 @@ + } + + this.setPhantomSize(compound.getInt("Size")); ++ // Paper start ++ if (compound.hasUUID("Paper.SpawningEntity")) { ++ this.spawningEntity = compound.getUUID("Paper.SpawningEntity"); ++ } ++ if (compound.contains("Paper.ShouldBurnInDay")) { ++ this.shouldBurnInDay = compound.getBoolean("Paper.ShouldBurnInDay"); ++ } ++ // Paper end + } + + @Override +@@ -174,6 +_,12 @@ + compound.putInt("AY", this.anchorPoint.getY()); + compound.putInt("AZ", this.anchorPoint.getZ()); + compound.putInt("Size", this.getPhantomSize()); ++ // Paper start ++ if (this.spawningEntity != null) { ++ compound.putUUID("Paper.SpawningEntity", this.spawningEntity); ++ } ++ compound.putBoolean("Paper.ShouldBurnInDay", shouldBurnInDay); ++ // Paper end + } + + @Override +@@ -222,6 +_,19 @@ + return targetingConditions.test(level, this, entity); + } + ++ // Paper start ++ @Nullable ++ java.util.UUID spawningEntity; ++ ++ @Nullable ++ public java.util.UUID getSpawningEntity() { ++ return this.spawningEntity; ++ } ++ public void setSpawningEntity(java.util.UUID entity) { this.spawningEntity = entity; } ++ private boolean shouldBurnInDay = true; ++ public boolean shouldBurnInDay() { return shouldBurnInDay; } ++ public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } ++ // Paper end + static enum AttackPhase { + CIRCLE, + SWOOP; +@@ -247,7 +_,8 @@ + + for (Player player : nearbyPlayers) { + if (Phantom.this.canAttack(serverLevel, player, TargetingConditions.DEFAULT)) { +- Phantom.this.setTarget(player); ++ if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.IS_INSOMNIAC.test(player)) // Paper - Add phantom creative and insomniac controls ++ Phantom.this.setTarget(player, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - reason + return true; + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Pillager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Pillager.java.patch new file mode 100644 index 0000000000..baac9f090b --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Pillager.java.patch @@ -0,0 +1,11 @@ +--- a/net/minecraft/world/entity/monster/Pillager.java ++++ b/net/minecraft/world/entity/monster/Pillager.java +@@ -214,7 +_,7 @@ + this.onItemPickup(entity); + ItemStack itemStack = this.inventory.addItem(item); + if (itemStack.isEmpty()) { +- entity.discard(); ++ entity.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause + } else { + item.setCount(itemStack.getCount()); + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Ravager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Ravager.java.patch new file mode 100644 index 0000000000..00100011ed --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Ravager.java.patch @@ -0,0 +1,31 @@ +--- a/net/minecraft/world/entity/monster/Ravager.java ++++ b/net/minecraft/world/entity/monster/Ravager.java +@@ -151,12 +_,19 @@ + BlockState blockState = serverLevel.getBlockState(blockPos); + Block block = blockState.getBlock(); + if (block instanceof LeavesBlock) { ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this, blockPos, blockState.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state ++ continue; ++ } ++ // CraftBukkit end + flag = serverLevel.destroyBlock(blockPos, true, this) || flag; + } + } + + if (!flag && this.onGround()) { ++ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API + this.jumpFromGround(); ++ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop + } + } + +@@ -257,7 +_,7 @@ + double d = entity.getX() - this.getX(); + double d1 = entity.getZ() - this.getZ(); + double max = Math.max(d * d + d1 * d1, 0.001); +- entity.push(d / max * 4.0, 0.2, d1 / max * 4.0); ++ entity.push(d / max * 4.0, 0.2, d1 / max * 4.0, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent + } + + @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch new file mode 100644 index 0000000000..8bd9da3693 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Shulker.java.patch @@ -0,0 +1,46 @@ +--- a/net/minecraft/world/entity/monster/Shulker.java ++++ b/net/minecraft/world/entity/monster/Shulker.java +@@ -274,7 +_,13 @@ + + @Override + public void stopRiding() { +- super.stopRiding(); ++ // Paper start - Force entity dismount during teleportation ++ this.stopRiding(false); ++ } ++ @Override ++ public void stopRiding(boolean suppressCancellation) { ++ super.stopRiding(suppressCancellation); ++ // Paper end - Force entity dismount during teleportation + if (this.level().isClientSide) { + this.clientOldAttachPosition = this.blockPosition(); + } +@@ -387,6 +_,14 @@ + && this.level().getWorldBorder().isWithinBounds(blockPos1) + && this.level().noCollision(this, new AABB(blockPos1).deflate(1.0E-6))) { + Direction direction = this.findAttachableSurface(blockPos1); ++ // CraftBukkit start ++ org.bukkit.event.entity.EntityTeleportEvent teleportEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTeleportEvent(this, blockPos1.getX(), blockPos1.getY(), blockPos1.getZ()); ++ if (teleportEvent.isCancelled() || teleportEvent.getTo() == null) { // Paper ++ return false; ++ } else { ++ blockPos1 = org.bukkit.craftbukkit.util.CraftLocation.toBlockPosition(teleportEvent.getTo()); ++ } ++ // CraftBukkit end + if (direction != null) { + this.unRide(); + this.setAttachFace(direction); +@@ -453,7 +_,12 @@ + if (shulker != null) { + shulker.setVariant(this.getVariant()); + shulker.moveTo(vec3); +- this.level().addFreshEntity(shulker); ++ // Paper start - Shulker duplicate event ++ if (!new io.papermc.paper.event.entity.ShulkerDuplicateEvent((org.bukkit.entity.Shulker) shulker.getBukkitEntity(), (org.bukkit.entity.Shulker) this.getBukkitEntity()).callEvent()) { ++ return; ++ } ++ // Paper end - Shulker duplicate event ++ this.level().addFreshEntity(shulker, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - the mysteries of life + } + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Silverfish.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Silverfish.java.patch new file mode 100644 index 0000000000..a8c9b55110 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Silverfish.java.patch @@ -0,0 +1,40 @@ +--- a/net/minecraft/world/entity/monster/Silverfish.java ++++ b/net/minecraft/world/entity/monster/Silverfish.java +@@ -119,7 +_,7 @@ + return true; + } else { + Player nearestPlayer = level.getNearestPlayer(pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5, 5.0, true); +- return nearestPlayer == null; ++ return !(nearestPlayer != null && !nearestPlayer.affectsSpawning) && nearestPlayer == null; // Paper - Affects Spawning API + } + } + +@@ -170,9 +_,14 @@ + BlockPos blockPos = BlockPos.containing(this.mob.getX(), this.mob.getY() + 0.5, this.mob.getZ()).relative(this.selectedDirection); + BlockState blockState = levelAccessor.getBlockState(blockPos); + if (InfestedBlock.isCompatibleHostBlock(blockState)) { ++ // CraftBukkit start ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockPos, InfestedBlock.infestedStateByHost(blockState))) { ++ return; ++ } ++ // CraftBukkit end + levelAccessor.setBlock(blockPos, InfestedBlock.infestedStateByHost(blockState), 3); + this.mob.spawnAnim(); +- this.mob.discard(); ++ this.mob.discard(org.bukkit.event.entity.EntityRemoveEvent.Cause.ENTER_BLOCK); // CraftBukkit - add Bukkit remove cause + } + } + } +@@ -212,6 +_,12 @@ + BlockState blockState = level.getBlockState(blockPos1); + Block block = blockState.getBlock(); + if (block instanceof InfestedBlock) { ++ // CraftBukkit start ++ BlockState afterState = getServerLevel(level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? blockState.getFluidState().createLegacyBlock() : ((InfestedBlock) block).hostStateByInfested(level.getBlockState(blockPos1)); // Paper - fix wrong block state ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockPos1, afterState)) { // Paper - fix wrong block state ++ continue; ++ } ++ // CraftBukkit end + if (getServerLevel(level).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { + level.destroyBlock(blockPos1, true, this.silverfish); + } else { diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Skeleton.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Skeleton.java.patch similarity index 76% rename from paper-server/patches/unapplied/net/minecraft/world/entity/monster/Skeleton.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/monster/Skeleton.java.patch index d17fea360f..e847a3c8fd 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Skeleton.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Skeleton.java.patch @@ -1,24 +1,23 @@ --- a/net/minecraft/world/entity/monster/Skeleton.java +++ b/net/minecraft/world/entity/monster/Skeleton.java -@@ -94,12 +94,19 @@ +@@ -89,11 +_,18 @@ } protected void doFreezeConversion() { -- this.convertTo(EntityType.STRAY, ConversionParams.single(this, true, true), (entityskeletonstray) -> { +- this.convertTo(EntityType.STRAY, ConversionParams.single(this, true, true), mob -> { + final Stray stray = this.convertTo(EntityType.STRAY, ConversionParams.single(this, true, true), (entityskeletonstray) -> { // Paper - Fix issues with mob conversion; reset conversion time to prevent event spam if (!this.isSilent()) { - this.level().levelEvent((Player) null, 1048, this.blockPosition(), 0); + this.level().levelEvent(null, 1048, this.blockPosition(), 0); } - - }); -+ }, org.bukkit.event.entity.EntityTransformEvent.TransformReason.FROZEN, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.FROZEN);// CraftBukkit - add spawn and transform reasons -+ ++ // CraftBukkit start - add spawn and transform reasons ++ }, org.bukkit.event.entity.EntityTransformEvent.TransformReason.FROZEN, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.FROZEN); + // Paper start - Fix issues with mob conversion; reset conversion time to prevent event spam + if (stray == null) { + this.conversionTime = 300; + } + // Paper end - Fix issues with mob conversion -+ ++ // CraftBukkit end - add spawn and transform reasons } @Override diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Slime.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Slime.java.patch new file mode 100644 index 0000000000..2d78bee973 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Slime.java.patch @@ -0,0 +1,219 @@ +--- a/net/minecraft/world/entity/monster/Slime.java ++++ b/net/minecraft/world/entity/monster/Slime.java +@@ -110,6 +_,7 @@ + super.addAdditionalSaveData(compound); + compound.putInt("Size", this.getSize() - 1); + compound.putBoolean("wasOnGround", this.wasOnGround); ++ compound.putBoolean("Paper.canWander", this.canWander); // Paper + } + + @Override +@@ -117,6 +_,11 @@ + this.setSize(compound.getInt("Size") + 1, false); + super.readAdditionalSaveData(compound); + this.wasOnGround = compound.getBoolean("wasOnGround"); ++ // Paper start ++ if (compound.contains("Paper.canWander")) { ++ this.canWander = compound.getBoolean("Paper.canWander"); ++ } ++ // Paper end + } + + public boolean isTiny() { +@@ -197,6 +_,13 @@ + + @Override + public void remove(Entity.RemovalReason reason) { ++ // CraftBukkit start - add Bukkit remove cause ++ this.remove(reason, null); ++ } ++ ++ @Override ++ public void remove(Entity.RemovalReason entity_removalreason, org.bukkit.event.entity.EntityRemoveEvent.Cause cause) { ++ // CraftBukkit end + int size = this.getSize(); + if (!this.level().isClientSide && size > 1 && this.isDeadOrDying()) { + float width = this.getDimensions(this.getPose()).width(); +@@ -204,18 +_,45 @@ + int i = size / 2; + int i1 = 2 + this.random.nextInt(3); + PlayerTeam team = this.getTeam(); ++ // CraftBukkit start ++ org.bukkit.event.entity.SlimeSplitEvent event = new org.bukkit.event.entity.SlimeSplitEvent((org.bukkit.entity.Slime) this.getBukkitEntity(), i1); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled() && event.getCount() > 0) { ++ i1 = event.getCount(); ++ } else { ++ super.remove(entity_removalreason, cause); // CraftBukkit - add Bukkit remove cause ++ return; ++ } ++ java.util.List slimes = new java.util.ArrayList<>(i1); ++ // CraftBukkit end + + for (int i2 = 0; i2 < i1; i2++) { + float f1 = (i2 % 2 - 0.5F) * f; + float f2 = (i2 / 2 - 0.5F) * f; +- this.convertTo(this.getType(), new ConversionParams(ConversionType.SPLIT_ON_DEATH, false, false, team), EntitySpawnReason.TRIGGERED, mob -> { ++ Slime converted = this.convertTo(this.getType(), new ConversionParams(ConversionType.SPLIT_ON_DEATH, false, false, team), EntitySpawnReason.TRIGGERED, (mob) -> { // CraftBukkit ++ mob.aware = this.aware; // Paper - Fix nerfed slime when splitting + mob.setSize(i, true); + mob.moveTo(this.getX() + f1, this.getY() + 0.5, this.getZ() + f2, this.random.nextFloat() * 360.0F, 0.0F); +- }); +- } ++ // CraftBukkit start ++ }, null, null); ++ if (converted != null) { ++ slimes.add(converted); ++ } ++ // CraftBukkit end ++ } ++ // CraftBukkit start ++ if (org.bukkit.craftbukkit.event.CraftEventFactory.callEntityTransformEvent(this, slimes, org.bukkit.event.entity.EntityTransformEvent.TransformReason.SPLIT).isCancelled()) { ++ super.remove(entity_removalreason, cause); // CraftBukkit - add Bukkit remove cause ++ return; ++ } ++ for (LivingEntity living : slimes) { ++ this.level().addFreshEntity(living, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SLIME_SPLIT); // CraftBukkit - SpawnReason ++ } ++ // CraftBukkit end + } + +- super.remove(reason); ++ super.remove(entity_removalreason, cause); // CraftBukkit - add Bukkit remove cause + } + + @Override +@@ -281,9 +_,13 @@ + return checkMobSpawnRules(entityType, level, spawnReason, pos, random); + } + ++ // Paper start - Replace rules for Height in Swamp Biome ++ final double maxHeightSwamp = level.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.surfaceBiome.maximum; ++ final double minHeightSwamp = level.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.surfaceBiome.minimum; ++ // Paper end + if (level.getBiome(pos).is(BiomeTags.ALLOWS_SURFACE_SLIME_SPAWNS) +- && pos.getY() > 50 +- && pos.getY() < 70 ++ && pos.getY() > minHeightSwamp // Paper - Replace rules for Height in Swamp Biome ++ && pos.getY() < maxHeightSwamp // Paper - Replace rules for Height in Swamp Biome + && random.nextFloat() < 0.5F + && random.nextFloat() < level.getMoonBrightness() + && level.getMaxLocalRawBrightness(pos) <= random.nextInt(8)) { +@@ -295,8 +_,11 @@ + } + + ChunkPos chunkPos = new ChunkPos(pos); +- boolean flag = WorldgenRandom.seedSlimeChunk(chunkPos.x, chunkPos.z, ((WorldGenLevel)level).getSeed(), 987234911L).nextInt(10) == 0; +- if (random.nextInt(10) == 0 && flag && pos.getY() < 40) { ++ boolean flag = level.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkPos.x, chunkPos.z, ((WorldGenLevel) level).getSeed(), level.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper ++ // Paper start - Replace rules for Height in Slime Chunks ++ final double maxHeightSlimeChunk = level.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.slimeChunk.maximum; ++ if (random.nextInt(10) == 0 && flag && pos.getY() < maxHeightSlimeChunk) { ++ // Paper end - Replace rules for Height in Slime Chunks + return checkMobSpawnRules(entityType, level, spawnReason, pos, random); + } + } +@@ -367,7 +_,16 @@ + @Override + public boolean canUse() { + LivingEntity target = this.slime.getTarget(); +- return target != null && this.slime.canAttack(target) && this.slime.getMoveControl() instanceof Slime.SlimeMoveControl; ++ ++ // Paper start - Slime pathfinder events ++ if (target == null || !target.isAlive()) { ++ return false; ++ } ++ if (!this.slime.canAttack(target)) { ++ return false; ++ } ++ return this.slime.getMoveControl() instanceof Slime.SlimeMoveControl && this.slime.canWander && new com.destroystokyo.paper.event.entity.SlimeTargetLivingEntityEvent((org.bukkit.entity.Slime) this.slime.getBukkitEntity(), (org.bukkit.entity.LivingEntity) target.getBukkitEntity()).callEvent(); ++ // Paper end - Slime pathfinder events + } + + @Override +@@ -379,7 +_,16 @@ + @Override + public boolean canContinueToUse() { + LivingEntity target = this.slime.getTarget(); +- return target != null && this.slime.canAttack(target) && --this.growTiredTimer > 0; ++ ++ // Paper start - Slime pathfinder events ++ if (target == null || !target.isAlive()) { ++ return false; ++ } ++ if (!this.slime.canAttack(target)) { ++ return false; ++ } ++ return --this.growTiredTimer > 0 && this.slime.canWander && new com.destroystokyo.paper.event.entity.SlimeTargetLivingEntityEvent((org.bukkit.entity.Slime) this.slime.getBukkitEntity(), (org.bukkit.entity.LivingEntity) target.getBukkitEntity()).callEvent(); ++ // Paper end - Slime pathfinder events + } + + @Override +@@ -398,6 +_,12 @@ + slimeMoveControl.setDirection(this.slime.getYRot(), this.slime.isDealsDamage()); + } + } ++ // Paper start - Slime pathfinder events; clear timer and target when goal resets ++ public void stop() { ++ this.growTiredTimer = 0; ++ this.slime.setTarget(null); ++ } ++ // Paper end - Slime pathfinder events + } + + static class SlimeFloatGoal extends Goal { +@@ -411,7 +_,7 @@ + + @Override + public boolean canUse() { +- return (this.slime.isInWater() || this.slime.isInLava()) && this.slime.getMoveControl() instanceof Slime.SlimeMoveControl; ++ return (this.slime.isInWater() || this.slime.isInLava()) && this.slime.getMoveControl() instanceof Slime.SlimeMoveControl && this.slime.canWander && new com.destroystokyo.paper.event.entity.SlimeSwimEvent((org.bukkit.entity.Slime) this.slime.getBukkitEntity()).callEvent(); // Paper - Slime pathfinder events + } + + @Override +@@ -441,7 +_,7 @@ + + @Override + public boolean canUse() { +- return !this.slime.isPassenger(); ++ return !this.slime.isPassenger() && this.slime.canWander && new com.destroystokyo.paper.event.entity.SlimeWanderEvent((org.bukkit.entity.Slime) this.slime.getBukkitEntity()).callEvent(); // Paper - Slime pathfinder events + } + + @Override +@@ -519,7 +_,7 @@ + + @Override + public boolean canUse() { +- return this.slime.getTarget() == null ++ return this.slime.getTarget() == null && this.slime.canWander // Paper - Slime pathfinder events + && (this.slime.onGround() || this.slime.isInWater() || this.slime.isInLava() || this.slime.hasEffect(MobEffects.LEVITATION)) + && this.slime.getMoveControl() instanceof Slime.SlimeMoveControl; + } +@@ -529,6 +_,11 @@ + if (--this.nextRandomizeTime <= 0) { + this.nextRandomizeTime = this.adjustedTickDelay(40 + this.slime.getRandom().nextInt(60)); + this.chosenDegrees = this.slime.getRandom().nextInt(360); ++ // Paper start - Slime pathfinder events ++ com.destroystokyo.paper.event.entity.SlimeChangeDirectionEvent event = new com.destroystokyo.paper.event.entity.SlimeChangeDirectionEvent((org.bukkit.entity.Slime) this.slime.getBukkitEntity(), this.chosenDegrees); ++ if (!this.slime.canWander || !event.callEvent()) return; ++ this.chosenDegrees = event.getNewYaw(); ++ // Paper end - Slime pathfinder events + } + + if (this.slime.getMoveControl() instanceof Slime.SlimeMoveControl slimeMoveControl) { +@@ -536,4 +_,14 @@ + } + } + } ++ // Paper start - Slime pathfinder events ++ private boolean canWander = true; ++ public boolean canWander() { ++ return canWander; ++ } ++ ++ public void setWander(boolean canWander) { ++ this.canWander = canWander; ++ } ++ // Paper end - Slime pathfinder events + } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/SpellcasterIllager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/SpellcasterIllager.java.patch similarity index 50% rename from paper-server/patches/unapplied/net/minecraft/world/entity/monster/SpellcasterIllager.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/monster/SpellcasterIllager.java.patch index 7e02fcf3a8..24fa757b5d 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/SpellcasterIllager.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/SpellcasterIllager.java.patch @@ -1,21 +1,11 @@ --- a/net/minecraft/world/entity/monster/SpellcasterIllager.java +++ b/net/minecraft/world/entity/monster/SpellcasterIllager.java -@@ -17,6 +17,9 @@ - import net.minecraft.world.entity.LivingEntity; - import net.minecraft.world.entity.ai.goal.Goal; - import net.minecraft.world.level.Level; -+// CraftBukkit start -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+// CraftBukkit end - - public abstract class SpellcasterIllager extends AbstractIllager { - -@@ -159,6 +162,11 @@ +@@ -208,6 +_,11 @@ public void tick() { - --this.attackWarmupDelay; + this.attackWarmupDelay--; if (this.attackWarmupDelay == 0) { + // CraftBukkit start -+ if (!CraftEventFactory.handleEntitySpellCastEvent(SpellcasterIllager.this, this.getSpell())) { ++ if (!org.bukkit.craftbukkit.event.CraftEventFactory.handleEntitySpellCastEvent(SpellcasterIllager.this, this.getSpell())) { + return; + } + // CraftBukkit end diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Spider.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Spider.java.patch similarity index 64% rename from paper-server/patches/unapplied/net/minecraft/world/entity/monster/Spider.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/monster/Spider.java.patch index 1dae9b0f57..8bf70bc126 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Spider.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Spider.java.patch @@ -1,29 +1,29 @@ --- a/net/minecraft/world/entity/monster/Spider.java +++ b/net/minecraft/world/entity/monster/Spider.java -@@ -82,7 +82,7 @@ +@@ -79,7 +_,7 @@ public void tick() { super.tick(); if (!this.level().isClientSide) { - this.setClimbing(this.horizontalCollision); + this.setClimbing(this.horizontalCollision && (this.level().paperConfig().entities.behavior.allowSpiderWorldBorderClimbing || !(ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.isCollidingWithBorder(this.level().getWorldBorder(), this.getBoundingBox().inflate(ca.spottedleaf.moonrise.patches.collisions.CollisionUtil.COLLISION_EPSILON)) && this.level().getWorldBorder().isInsideCloseToBorder(this, this.getBoundingBox())))); // Paper - Add config option for spider worldborder climbing (Inflate by +EPSILON as collision will just barely place us outside border) } - } -@@ -126,7 +126,7 @@ + +@@ -121,7 +_,7 @@ @Override - public boolean canBeAffected(MobEffectInstance effect) { -- return effect.is(MobEffects.POISON) ? false : super.canBeAffected(effect); -+ return effect.is(MobEffects.POISON) && this.level().paperConfig().entities.mobEffects.spidersImmuneToPoisonEffect ? false : super.canBeAffected(effect); // Paper - Add config for mobs immune to default effects + public boolean canBeAffected(MobEffectInstance potioneffect) { +- return !potioneffect.is(MobEffects.POISON) && super.canBeAffected(potioneffect); ++ return potioneffect.is(MobEffects.POISON) && this.level().paperConfig().entities.mobEffects.spidersImmuneToPoisonEffect ? false : super.canBeAffected(potioneffect); // Paper - Add config for mobs immune to default effects } public boolean isClimbing() { -@@ -172,7 +172,7 @@ - Holder holder = entityspider_groupdataspider.effect; - +@@ -165,7 +_,7 @@ + if (spawnGroupData instanceof Spider.SpiderEffectsGroupData spiderEffectsGroupData) { + Holder holder = spiderEffectsGroupData.effect; if (holder != null) { - this.addEffect(new MobEffectInstance(holder, -1)); -+ this.addEffect(new MobEffectInstance(holder, -1), null, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.SPIDER_SPAWN, world instanceof net.minecraft.server.level.ServerLevel); // CraftBukkit ++ this.addEffect(new MobEffectInstance(holder, -1), null, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.SPIDER_SPAWN, level instanceof net.minecraft.server.level.ServerLevel); // CraftBukkit } } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Strider.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Strider.java.patch similarity index 57% rename from paper-server/patches/unapplied/net/minecraft/world/entity/monster/Strider.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/monster/Strider.java.patch index fbc85b5bbe..63f135a7cc 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Strider.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Strider.java.patch @@ -1,12 +1,12 @@ --- a/net/minecraft/world/entity/monster/Strider.java +++ b/net/minecraft/world/entity/monster/Strider.java -@@ -350,7 +350,14 @@ - - boolean flag2 = flag1; - -- this.setSuffocating(!flag || flag2); +@@ -309,7 +_,14 @@ + || blockStateOnLegacy.is(BlockTags.STRIDER_WARM_BLOCKS) + || this.getFluidHeight(FluidTags.LAVA) > 0.0; + boolean flag1 = this.getVehicle() instanceof Strider strider && strider.isSuffocating(); +- this.setSuffocating(!flag || flag1); + // CraftBukkit start -+ boolean suffocating = !flag || flag2; ++ boolean suffocating = !flag || flag1; + if (suffocating ^ this.isSuffocating()) { + if (org.bukkit.craftbukkit.event.CraftEventFactory.callStriderTemperatureChangeEvent(this, suffocating)) { + this.setSuffocating(suffocating); diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Vex.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Vex.java.patch similarity index 52% rename from paper-server/patches/unapplied/net/minecraft/world/entity/monster/Vex.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/monster/Vex.java.patch index c2c4e27616..415806e46f 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Vex.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Vex.java.patch @@ -1,18 +1,6 @@ --- a/net/minecraft/world/entity/monster/Vex.java +++ b/net/minecraft/world/entity/monster/Vex.java -@@ -354,7 +354,10 @@ - for (int i = 0; i < 3; ++i) { - BlockPos blockposition1 = blockposition.offset(Vex.this.random.nextInt(15) - 7, Vex.this.random.nextInt(11) - 5, Vex.this.random.nextInt(15) - 7); - -- if (Vex.this.level().isEmptyBlock(blockposition1)) { -+ // Paper start - Don't load chunks -+ final net.minecraft.world.level.block.state.BlockState blockState = Vex.this.level().getBlockStateIfLoaded(blockposition1); -+ if (blockState != null && blockState.isAir()) { -+ // Paper end - Don't load chunks - Vex.this.moveControl.setWantedPosition((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.5D, (double) blockposition1.getZ() + 0.5D, 0.25D); - if (Vex.this.getTarget() == null) { - Vex.this.getLookControl().setLookAt((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.5D, (double) blockposition1.getZ() + 0.5D, 180.0F, 20.0F); -@@ -381,7 +384,7 @@ +@@ -296,7 +_,7 @@ @Override public void start() { @@ -21,3 +9,15 @@ super.start(); } } +@@ -355,7 +_,10 @@ + + for (int i = 0; i < 3; i++) { + BlockPos blockPos = boundOrigin.offset(Vex.this.random.nextInt(15) - 7, Vex.this.random.nextInt(11) - 5, Vex.this.random.nextInt(15) - 7); +- if (Vex.this.level().isEmptyBlock(blockPos)) { ++ // Paper start - Don't load chunks ++ final net.minecraft.world.level.block.state.BlockState blockState = Vex.this.level().getBlockStateIfLoaded(blockPos); ++ if (blockState != null && blockState.isAir()) { ++ // Paper end - Don't load chunks + Vex.this.moveControl.setWantedPosition(blockPos.getX() + 0.5, blockPos.getY() + 0.5, blockPos.getZ() + 0.5, 0.25); + if (Vex.this.getTarget() == null) { + Vex.this.getLookControl().setLookAt(blockPos.getX() + 0.5, blockPos.getY() + 0.5, blockPos.getZ() + 0.5, 180.0F, 20.0F); diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Vindicator.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Vindicator.java.patch similarity index 97% rename from paper-server/patches/unapplied/net/minecraft/world/entity/monster/Vindicator.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/monster/Vindicator.java.patch index e652ce7a7e..70543fd76e 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Vindicator.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Vindicator.java.patch @@ -1,6 +1,6 @@ --- a/net/minecraft/world/entity/monster/Vindicator.java +++ b/net/minecraft/world/entity/monster/Vindicator.java -@@ -184,7 +184,7 @@ +@@ -184,7 +_,7 @@ static class VindicatorBreakDoorGoal extends BreakDoorGoal { public VindicatorBreakDoorGoal(Mob mob) { diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Witch.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Witch.java.patch similarity index 64% rename from paper-server/patches/unapplied/net/minecraft/world/entity/monster/Witch.java.patch rename to paper-server/patches/sources/net/minecraft/world/entity/monster/Witch.java.patch index 6939fca599..e1dbaaaa93 100644 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Witch.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Witch.java.patch @@ -1,23 +1,22 @@ --- a/net/minecraft/world/entity/monster/Witch.java +++ b/net/minecraft/world/entity/monster/Witch.java -@@ -124,9 +124,15 @@ - +@@ -122,8 +_,14 @@ + ItemStack mainHandItem = this.getMainHandItem(); this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY); - PotionContents potioncontents = (PotionContents) itemstack.get(DataComponents.POTION_CONTENTS); + PotionContents potionContents = mainHandItem.get(DataComponents.POTION_CONTENTS); + // Paper start - WitchConsumePotionEvent -+ if (itemstack.is(Items.POTION)) { ++ if (mainHandItem.is(Items.POTION)) { + com.destroystokyo.paper.event.entity.WitchConsumePotionEvent event = new com.destroystokyo.paper.event.entity.WitchConsumePotionEvent((org.bukkit.entity.Witch) this.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); -+ potioncontents = event.callEvent() ? org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getPotion()).get(DataComponents.POTION_CONTENTS) : null; ++ potionContents = event.callEvent() ? org.bukkit.craftbukkit.inventory.CraftItemStack.unwrap(event.getPotion()).get(DataComponents.POTION_CONTENTS) : null; + } + // Paper end - WitchConsumePotionEvent - - if (itemstack.is(Items.POTION) && potioncontents != null) { -- potioncontents.forEachEffect(this::addEffect); -+ potioncontents.forEachEffect((effect) -> this.addEffect(effect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK)); // CraftBukkit + if (mainHandItem.is(Items.POTION) && potionContents != null) { +- potionContents.forEachEffect(this::addEffect); ++ potionContents.forEachEffect((effect) -> this.addEffect(effect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK)); // CraftBukkit } this.gameEvent(GameEvent.DRINK); -@@ -146,17 +152,7 @@ +@@ -147,26 +_,7 @@ } if (holder != null) { @@ -25,23 +24,30 @@ - this.usingTime = this.getMainHandItem().getUseDuration(this); - this.setUsingItem(true); - if (!this.isSilent()) { -- this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), SoundEvents.WITCH_DRINK, this.getSoundSource(), 1.0F, 0.8F + this.random.nextFloat() * 0.4F); +- this.level() +- .playSound( +- null, +- this.getX(), +- this.getY(), +- this.getZ(), +- SoundEvents.WITCH_DRINK, +- this.getSoundSource(), +- 1.0F, +- 0.8F + this.random.nextFloat() * 0.4F +- ); - } - -- AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED); -- -- attributemodifiable.removeModifier(Witch.SPEED_MODIFIER_DRINKING_ID); -- attributemodifiable.addTransientModifier(Witch.SPEED_MODIFIER_DRINKING); +- AttributeInstance attribute = this.getAttribute(Attributes.MOVEMENT_SPEED); +- attribute.removeModifier(SPEED_MODIFIER_DRINKING_ID); +- attribute.addTransientModifier(SPEED_MODIFIER_DRINKING); + this.setDrinkingPotion(PotionContents.createItemStack(Items.POTION, holder)); // Paper - logic moved into setDrinkingPotion, copy exact impl into the method and then comment out } } -@@ -166,7 +162,24 @@ - } - +@@ -178,6 +_,23 @@ super.aiStep(); -+ } -+ + } + + // Paper start - moved to its own method + public void setDrinkingPotion(ItemStack potion) { + potion = org.bukkit.craftbukkit.event.CraftEventFactory.handleWitchReadyPotionEvent(this, potion); @@ -56,22 +62,23 @@ + + attributemodifiable.removeModifier(Witch.SPEED_MODIFIER_DRINKING_ID); + attributemodifiable.addTransientModifier(Witch.SPEED_MODIFIER_DRINKING); - } ++ } + // Paper end - ++ @Override public SoundEvent getCelebrateSound() { -@@ -231,6 +244,13 @@ - ServerLevel worldserver = (ServerLevel) world; - ItemStack itemstack = PotionContents.createItemStack(Items.SPLASH_POTION, holder); + return SoundEvents.WITCH_CELEBRATE; +@@ -244,6 +_,13 @@ + if (this.level() instanceof ServerLevel serverLevel) { + ItemStack itemStack = PotionContents.createItemStack(Items.SPLASH_POTION, holder); + // Paper start - WitchThrowPotionEvent + com.destroystokyo.paper.event.entity.WitchThrowPotionEvent event = new com.destroystokyo.paper.event.entity.WitchThrowPotionEvent((org.bukkit.entity.Witch) this.getBukkitEntity(), (org.bukkit.entity.LivingEntity) target.getBukkitEntity(), org.bukkit.craftbukkit.inventory.CraftItemStack.asCraftMirror(itemstack)); + if (!event.callEvent()) { + return; + } -+ itemstack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getPotion()); -+ // Paper end - WitchThrowPotionEvent - Projectile.spawnProjectileUsingShoot(ThrownPotion::new, worldserver, itemstack, this, d0, d1 + d3 * 0.2D, d2, 0.75F, 8.0F); ++ itemStack = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(event.getPotion()); ++ // Paper end - WitchThrowPotionEven + Projectile.spawnProjectileUsingShoot(ThrownPotion::new, serverLevel, itemStack, this, d, d1 + squareRoot * 0.2, d2, 0.75F, 8.0F); } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/WitherSkeleton.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/WitherSkeleton.java.patch new file mode 100644 index 0000000000..9780923155 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/WitherSkeleton.java.patch @@ -0,0 +1,19 @@ +--- a/net/minecraft/world/entity/monster/WitherSkeleton.java ++++ b/net/minecraft/world/entity/monster/WitherSkeleton.java +@@ -105,7 +_,7 @@ + return false; + } else { + if (source instanceof LivingEntity) { +- ((LivingEntity)source).addEffect(new MobEffectInstance(MobEffects.WITHER, 200), this); ++ ((LivingEntity)source).addEffect(new MobEffectInstance(MobEffects.WITHER, 200), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit + } + + return true; +@@ -121,6 +_,6 @@ + + @Override + public boolean canBeAffected(MobEffectInstance potioneffect) { +- return !potioneffect.is(MobEffects.WITHER) && super.canBeAffected(potioneffect); ++ return potioneffect.is(MobEffects.WITHER) && this.level().paperConfig().entities.mobEffects.immuneToWitherEffect.witherSkeleton ? false : super.canBeAffected(potioneffect); // Paper - Add config for mobs immune to default effects + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/Zombie.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/Zombie.java.patch new file mode 100644 index 0000000000..1b2d06c538 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/Zombie.java.patch @@ -0,0 +1,239 @@ +--- a/net/minecraft/world/entity/monster/Zombie.java ++++ b/net/minecraft/world/entity/monster/Zombie.java +@@ -68,9 +_,7 @@ + + public class Zombie extends Monster { + private static final ResourceLocation SPEED_MODIFIER_BABY_ID = ResourceLocation.withDefaultNamespace("baby"); +- private static final AttributeModifier SPEED_MODIFIER_BABY = new AttributeModifier( +- SPEED_MODIFIER_BABY_ID, 0.5, AttributeModifier.Operation.ADD_MULTIPLIED_BASE +- ); ++ private final AttributeModifier babyModifier = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_ID, this.level().paperConfig().entities.behavior.babyZombieMovementModifier, AttributeModifier.Operation.ADD_MULTIPLIED_BASE); // Paper - Make baby speed configurable + private static final ResourceLocation REINFORCEMENT_CALLER_CHARGE_ID = ResourceLocation.withDefaultNamespace("reinforcement_caller_charge"); + private static final AttributeModifier ZOMBIE_REINFORCEMENT_CALLEE_CHARGE = new AttributeModifier( + ResourceLocation.withDefaultNamespace("reinforcement_callee_charge"), -0.05F, AttributeModifier.Operation.ADD_VALUE +@@ -87,13 +_,16 @@ + private static final EntityDimensions BABY_DIMENSIONS = EntityType.ZOMBIE.getDimensions().scale(0.5F).withEyeHeight(0.93F); + private static final float BREAK_DOOR_CHANCE = 0.1F; + public static final Predicate DOOR_BREAKING_PREDICATE = difficulty -> difficulty == Difficulty.HARD; +- private final BreakDoorGoal breakDoorGoal = new BreakDoorGoal(this, DOOR_BREAKING_PREDICATE); ++ private final BreakDoorGoal breakDoorGoal; // Paper - move down + private boolean canBreakDoors; + private int inWaterTime; + public int conversionTime; ++ // private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field // Paper - remove anti tick skipping measures / wall time ++ private boolean shouldBurnInDay = true; // Paper - Add more Zombie API + + public Zombie(EntityType entityType, Level level) { + super(entityType, level); ++ this.breakDoorGoal = new BreakDoorGoal(this, com.google.common.base.Predicates.in(level.paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(entityType, level.paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.ZOMBIE)))); // Paper - Configurable door breaking difficulty + } + + public Zombie(Level level) { +@@ -102,7 +_,7 @@ + + @Override + protected void registerGoals() { +- this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0, 3)); ++ if (this.level().paperConfig().entities.behavior.zombiesTargetTurtleEggs) this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0, 3)); // Paper - Add zombie targets turtle egg config + this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); + this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); + this.addBehaviourGoals(); +@@ -114,7 +_,7 @@ + this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0)); + this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers(ZombifiedPiglin.class)); + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); +- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); ++ if (this.level().spigotConfig.zombieAggressiveTowardsVillager) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); // Spigot + this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); + this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR)); + } +@@ -168,11 +_,16 @@ + + @Override + protected int getBaseExperienceReward(ServerLevel level) { ++ final int previousReward = this.xpReward; // Paper - store previous value to reset after calculating XP reward + if (this.isBaby()) { + this.xpReward = (int)(this.xpReward * 2.5); + } + +- return super.getBaseExperienceReward(level); ++ // Paper start - store previous value to reset after calculating XP reward ++ int reward = super.getBaseExperienceReward(level); ++ this.xpReward = previousReward; ++ return reward; ++ // Paper end - store previous value to reset after calculating XP reward + } + + @Override +@@ -180,9 +_,9 @@ + this.getEntityData().set(DATA_BABY_ID, childZombie); + if (this.level() != null && !this.level().isClientSide) { + AttributeInstance attribute = this.getAttribute(Attributes.MOVEMENT_SPEED); +- attribute.removeModifier(SPEED_MODIFIER_BABY_ID); ++ attribute.removeModifier(this.babyModifier.id()); // Paper - Make baby speed configurable + if (childZombie) { +- attribute.addTransientModifier(SPEED_MODIFIER_BABY); ++ attribute.addTransientModifier(this.babyModifier); // Paper - Make baby speed configurable + } + } + } +@@ -221,6 +_,7 @@ + } + + super.tick(); ++ // this.lastTick = MinecraftServer.currentTick; // CraftBukkit // Paper - remove anti tick skipping measures / wall time + } + + @Override +@@ -251,7 +_,14 @@ + super.aiStep(); + } + ++ // Paper start - Add more Zombie API ++ public void stopDrowning() { ++ this.conversionTime = -1; ++ this.getEntityData().set(Zombie.DATA_DROWNED_CONVERSION_ID, false); ++ } ++ // Paper end - Add more Zombie API + public void startUnderWaterConversion(int conversionTime) { ++ // this.lastTick = MinecraftServer.currentTick; // CraftBukkit // Paper - remove anti tick skipping measures / wall tim + this.conversionTime = conversionTime; + this.getEntityData().set(DATA_DROWNED_CONVERSION_ID, true); + } +@@ -264,31 +_,49 @@ + } + + protected void convertToZombieType(EntityType entityType) { +- this.convertTo( ++ Zombie converted = this.convertTo( // CraftBukkit + entityType, + ConversionParams.single(this, true, true), +- zombie -> zombie.handleAttributes(zombie.level().getCurrentDifficultyAt(zombie.blockPosition()).getSpecialMultiplier()) +- ); ++ // CraftBukkit start ++ zombie -> {zombie.handleAttributes(zombie.level().getCurrentDifficultyAt(zombie.blockPosition()).getSpecialMultiplier());}, ++ org.bukkit.event.entity.EntityTransformEvent.TransformReason.DROWNED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.DROWNED); ++ if (converted == null) { ++ ((org.bukkit.entity.Zombie) this.getBukkitEntity()).setConversionTime(-1); // CraftBukkit - SPIGOT-5208: End conversion to stop event spam ++ } ++ // CraftBukkit end + } + + @VisibleForTesting + public boolean convertVillagerToZombieVillager(ServerLevel level, Villager villager) { ++ // CraftBukkit start ++ return Zombie.convertVillagerToZombieVillager(level, villager, this.blockPosition(), this.isSilent(), org.bukkit.event.entity.EntityTransformEvent.TransformReason.INFECTION, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.INFECTION) != null; ++ } ++ ++ public static ZombieVillager convertVillagerToZombieVillager(ServerLevel level, Villager villager, net.minecraft.core.BlockPos blockPosition, boolean silent, org.bukkit.event.entity.EntityTransformEvent.TransformReason transformReason, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason spawnReason) { ++ // CraftBukkit end + ZombieVillager zombieVillager = villager.convertTo(EntityType.ZOMBIE_VILLAGER, ConversionParams.single(villager, true, true), mob -> { + mob.finalizeSpawn(level, level.getCurrentDifficultyAt(mob.blockPosition()), EntitySpawnReason.CONVERSION, new Zombie.ZombieGroupData(false, true)); + mob.setVillagerData(villager.getVillagerData()); + mob.setGossips(villager.getGossips().store(NbtOps.INSTANCE)); + mob.setTradeOffers(villager.getOffers().copy()); + mob.setVillagerXp(villager.getVillagerXp()); +- if (!this.isSilent()) { +- level.levelEvent(null, 1026, this.blockPosition(), 0); ++ // CraftBukkit start ++ if (!silent) { ++ level.levelEvent(null, 1026, blockPosition, 0); + } ++ // CraftBukkit end + }); +- return zombieVillager != null; ++ return zombieVillager; + } + + public boolean isSunSensitive() { +- return true; +- } ++ return this.shouldBurnInDay; // Paper - Add more Zombie API ++ } ++ // Paper start - Add more Zombie API ++ public void setShouldBurnInDay(boolean shouldBurnInDay) { ++ this.shouldBurnInDay = shouldBurnInDay; ++ } ++ // Paper end - Add more Zombie API + + @Override + public boolean hurtServer(ServerLevel level, DamageSource damageSource, float amount) { +@@ -321,13 +_,13 @@ + if (SpawnPlacements.isSpawnPositionOk(type, level, blockPos) + && SpawnPlacements.checkSpawnRules(type, level, EntitySpawnReason.REINFORCEMENT, blockPos, level.random)) { + zombie.setPos(i1, i2, i3); +- if (!level.hasNearbyAlivePlayer(i1, i2, i3, 7.0) ++ if (!level.hasNearbyAlivePlayerThatAffectsSpawning(i1, i2, i3, 7.0) // Paper - affects spawning api + && level.isUnobstructed(zombie) + && level.noCollision(zombie) + && (zombie.canSpawnInLiquids() || !level.containsAnyLiquid(zombie.getBoundingBox()))) { +- zombie.setTarget(target); ++ zombie.setTarget(target, org.bukkit.event.entity.EntityTargetEvent.TargetReason.REINFORCEMENT_TARGET, true); // CraftBukkit + zombie.finalizeSpawn(level, level.getCurrentDifficultyAt(zombie.blockPosition()), EntitySpawnReason.REINFORCEMENT, null); +- level.addFreshEntityWithPassengers(zombie); ++ level.addFreshEntityWithPassengers(zombie, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.REINFORCEMENTS); // CraftBukkit + AttributeInstance attribute = this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE); + AttributeModifier modifier = attribute.getModifier(REINFORCEMENT_CALLER_CHARGE_ID); + double d = modifier != null ? modifier.amount() : 0.0; +@@ -352,7 +_,14 @@ + if (flag) { + float effectiveDifficulty = this.level().getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty(); + if (this.getMainHandItem().isEmpty() && this.isOnFire() && this.random.nextFloat() < effectiveDifficulty * 0.3F) { +- source.igniteForSeconds(2 * (int)effectiveDifficulty); ++ // CraftBukkit start ++ org.bukkit.event.entity.EntityCombustByEntityEvent event = new org.bukkit.event.entity.EntityCombustByEntityEvent(this.getBukkitEntity(), source.getBukkitEntity(), (float) (2 * (int)effectiveDifficulty)); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ ++ if (!event.isCancelled()) { ++ source.igniteForSeconds(event.getDuration(), false); ++ } ++ // CraftBukkit end + } + } + +@@ -412,6 +_,7 @@ + compound.putBoolean("CanBreakDoors", this.canBreakDoors()); + compound.putInt("InWaterTime", this.isInWater() ? this.inWaterTime : -1); + compound.putInt("DrownedConversionTime", this.isUnderWaterConverting() ? this.conversionTime : -1); ++ compound.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Paper - Add more Zombie API + } + + @Override +@@ -423,12 +_,18 @@ + if (compound.contains("DrownedConversionTime", 99) && compound.getInt("DrownedConversionTime") > -1) { + this.startUnderWaterConversion(compound.getInt("DrownedConversionTime")); + } ++ // Paper start - Add more Zombie API ++ if (compound.contains("Paper.ShouldBurnInDay")) { ++ this.shouldBurnInDay = compound.getBoolean("Paper.ShouldBurnInDay"); ++ } ++ // Paper end - Add more Zombie API + } + + @Override + public boolean killedEntity(ServerLevel level, LivingEntity entity) { + boolean flag = super.killedEntity(level, entity); +- if ((level.getDifficulty() == Difficulty.NORMAL || level.getDifficulty() == Difficulty.HARD) && entity instanceof Villager villager) { ++ final double fallbackChance = level.getDifficulty() == Difficulty.HARD ? 100d : level.getDifficulty() == Difficulty.NORMAL ? 50d : 0d; // Paper - Configurable chance of villager zombie infection ++ if (this.random.nextDouble() * 100 < level.paperConfig().entities.behavior.zombieVillagerInfectionChance.or(fallbackChance) && entity instanceof Villager villager) { // Paper - Configurable chance of villager zombie infection + if (level.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) { + return flag; + } +@@ -465,7 +_,7 @@ + spawnGroupData = super.finalizeSpawn(level, difficulty, spawnReason, spawnGroupData); + float specialMultiplier = difficulty.getSpecialMultiplier(); + if (spawnReason != EntitySpawnReason.CONVERSION) { +- this.setCanPickUpLoot(random.nextFloat() < 0.55F * specialMultiplier); ++ this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.zombies || random.nextFloat() < 0.55F * specialMultiplier); // Paper - Add world settings for mobs picking up loot + } + + if (spawnGroupData == null) { +@@ -492,7 +_,7 @@ + chicken1.finalizeSpawn(level, difficulty, EntitySpawnReason.JOCKEY, null); + chicken1.setChickenJockey(true); + this.startRiding(chicken1); +- level.addFreshEntity(chicken1); ++ level.addFreshEntity(chicken1, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.MOUNT); // CraftBukkit + } + } + } diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch new file mode 100644 index 0000000000..53b5b1fca0 --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/ZombieVillager.java.patch @@ -0,0 +1,107 @@ +--- a/net/minecraft/world/entity/monster/ZombieVillager.java ++++ b/net/minecraft/world/entity/monster/ZombieVillager.java +@@ -33,6 +_,7 @@ + import net.minecraft.world.entity.SlotAccess; + import net.minecraft.world.entity.SpawnGroupData; + import net.minecraft.world.entity.ai.village.ReputationEventType; ++import net.minecraft.world.entity.npc.Villager; + import net.minecraft.world.entity.npc.VillagerData; + import net.minecraft.world.entity.npc.VillagerDataHolder; + import net.minecraft.world.entity.npc.VillagerProfession; +@@ -68,6 +_,7 @@ + @Nullable + private MerchantOffers tradeOffers; + private int villagerXp; ++ private int lastTick = net.minecraft.server.MinecraftServer.currentTick; // CraftBukkit - add field + + public ZombieVillager(EntityType entityType, Level level) { + super(entityType, level); +@@ -140,6 +_,11 @@ + public void tick() { + if (!this.level().isClientSide && this.isAlive() && this.isConverting()) { + int conversionProgress = this.getConversionProgress(); ++ // CraftBukkit start - Use wall time instead of ticks for villager conversion ++ // TODO: WE WANT TO REMOVE THIS? I THOUGHT WE REMOVED IT. ++ int elapsedTicks = net.minecraft.server.MinecraftServer.currentTick - this.lastTick; ++ conversionProgress *= elapsedTicks; ++ // CraftBukkit end + this.villagerConversionTime -= conversionProgress; + if (this.villagerConversionTime <= 0) { + this.finishConversion((ServerLevel)this.level()); +@@ -147,6 +_,7 @@ + } + + super.tick(); ++ this.lastTick = net.minecraft.server.MinecraftServer.currentTick; // CraftBukkit + } + + @Override +@@ -183,12 +_,20 @@ + } + + public void startConverting(@Nullable UUID conversionStarter, int villagerConversionTime) { ++ // Paper start - missing entity behaviour api - converting without entity event ++ this.startConverting(conversionStarter, villagerConversionTime, true); ++ } ++ ++ public void startConverting(@Nullable UUID conversionStarter, int villagerConversionTime, boolean broadcastEntityEvent) { ++ // Paper end - missing entity behaviour api - converting without entity event + this.conversionStarter = conversionStarter; + this.villagerConversionTime = villagerConversionTime; + this.getEntityData().set(DATA_CONVERTING_ID, true); +- this.removeEffect(MobEffects.WEAKNESS); +- this.addEffect(new MobEffectInstance(MobEffects.DAMAGE_BOOST, villagerConversionTime, Math.min(this.level().getDifficulty().getId() - 1, 0))); +- this.level().broadcastEntityEvent(this, (byte)16); ++ // CraftBukkit start ++ this.removeEffect(MobEffects.WEAKNESS, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); ++ this.addEffect(new MobEffectInstance(MobEffects.DAMAGE_BOOST, villagerConversionTime, Math.min(this.level().getDifficulty().getId() - 1, 0)), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); ++ // CraftBukkit end ++ if (broadcastEntityEvent) this.level().broadcastEntityEvent(this, (byte)16); // Paper - missing entity behaviour api - converting without entity event + } + + @Override +@@ -213,7 +_,7 @@ + } + + private void finishConversion(ServerLevel serverLevel) { +- this.convertTo( ++ Villager converted = this.convertTo( // CraftBukkit + EntityType.VILLAGER, + ConversionParams.single(this, false, false), + villager -> { +@@ -223,6 +_,7 @@ + SlotAccess slot = villager.getSlot(equipmentSlot.getIndex() + 300); + slot.set(this.getItemBySlot(equipmentSlot)); + } ++ this.forceDrops = false; // CraftBukkit + + villager.setVillagerData(this.getVillagerData()); + if (this.gossips != null) { +@@ -237,19 +_,24 @@ + villager.finalizeSpawn(serverLevel, serverLevel.getCurrentDifficultyAt(villager.blockPosition()), EntitySpawnReason.CONVERSION, null); + villager.refreshBrain(serverLevel); + if (this.conversionStarter != null) { +- Player playerByUuid = serverLevel.getPlayerByUUID(this.conversionStarter); ++ Player playerByUuid = serverLevel.getGlobalPlayerByUUID(this.conversionStarter); // Paper - check global player list where appropriate + if (playerByUuid instanceof ServerPlayer) { + CriteriaTriggers.CURED_ZOMBIE_VILLAGER.trigger((ServerPlayer)playerByUuid, this, villager); + serverLevel.onReputationEvent(ReputationEventType.ZOMBIE_VILLAGER_CURED, playerByUuid, villager); + } + } + +- villager.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0)); ++ villager.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); // CraftBukkit + if (!this.isSilent()) { + serverLevel.levelEvent(null, 1027, this.blockPosition(), 0); + } +- } ++ }, org.bukkit.event.entity.EntityTransformEvent.TransformReason.CURED, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.CURED // CraftBukkit + ); ++ // CraftBukkit start ++ if (converted == null) { ++ ((org.bukkit.entity.ZombieVillager) this.getBukkitEntity()).setConversionTime(-1); // SPIGOT-5208: End conversion to stop event spam ++ } ++ // CraftBukkit end + } + + @VisibleForTesting diff --git a/paper-server/patches/sources/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch b/paper-server/patches/sources/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch new file mode 100644 index 0000000000..dca58ab24d --- /dev/null +++ b/paper-server/patches/sources/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch @@ -0,0 +1,62 @@ +--- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java ++++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java +@@ -56,6 +_,7 @@ + private static final int ALERT_RANGE_Y = 10; + private static final UniformInt ALERT_INTERVAL = TimeUtil.rangeOfSeconds(4, 6); + private int ticksUntilNextAlert; ++ private HurtByTargetGoal pathfinderGoalHurtByTarget; // Paper - fix PigZombieAngerEvent cancellation + + public ZombifiedPiglin(EntityType entityType, Level level) { + super(entityType, level); +@@ -71,7 +_,7 @@ + protected void addBehaviourGoals() { + this.goalSelector.addGoal(2, new ZombieAttackGoal(this, 1.0, false)); + this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0)); +- this.targetSelector.addGoal(1, new HurtByTargetGoal(this).setAlertOthers()); ++ this.targetSelector.addGoal(1, pathfinderGoalHurtByTarget = (new HurtByTargetGoal(this)).setAlertOthers()); // Paper - fix PigZombieAngerEvent cancellation + this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); + this.targetSelector.addGoal(3, new ResetUniversalAngerTargetGoal<>(this, true)); + } +@@ -148,7 +_,7 @@ + .filter(zombifiedPiglin -> zombifiedPiglin != this) + .filter(zombifiedPiglin -> zombifiedPiglin.getTarget() == null) + .filter(zombifiedPiglin -> !zombifiedPiglin.isAlliedTo(this.getTarget())) +- .forEach(zombifiedPiglin -> zombifiedPiglin.setTarget(this.getTarget())); ++ .forEach(zombifiedPiglin -> zombifiedPiglin.setTarget(this.getTarget(), org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY, true)); // CraftBukkit + } + + private void playAngerSound() { +@@ -156,7 +_,7 @@ + } + + @Override +- public void setTarget(@Nullable LivingEntity livingEntity) { ++ public boolean setTarget(@Nullable LivingEntity livingEntity, org.bukkit.event.entity.EntityTargetEvent.TargetReason reason, boolean fireEvent) { // CraftBukkit - signature + if (this.getTarget() == null && livingEntity != null) { + this.playFirstAngerSoundIn = FIRST_ANGER_SOUND_DELAY.sample(this.random); + this.ticksUntilNextAlert = ALERT_INTERVAL.sample(this.random); +@@ -166,12 +_,22 @@ + this.setLastHurtByPlayer((Player)livingEntity); + } + +- super.setTarget(livingEntity); ++ return super.setTarget(livingEntity, reason, fireEvent); // CraftBukkit + } + + @Override + public void startPersistentAngerTimer() { +- this.setRemainingPersistentAngerTime(PERSISTENT_ANGER_TIME.sample(this.random)); ++ // CraftBukkit start ++ net.minecraft.world.entity.Entity entity = ((ServerLevel) this.level()).getEntity(this.getPersistentAngerTarget()); ++ org.bukkit.event.entity.PigZombieAngerEvent event = new org.bukkit.event.entity.PigZombieAngerEvent((org.bukkit.entity.PigZombie) this.getBukkitEntity(), (entity == null) ? null : entity.getBukkitEntity(), ZombifiedPiglin.PERSISTENT_ANGER_TIME.sample(this.random)); ++ this.level().getCraftServer().getPluginManager().callEvent(event); ++ if (event.isCancelled()) { ++ this.setPersistentAngerTarget(null); ++ pathfinderGoalHurtByTarget.stop(); // Paper - fix PigZombieAngerEvent cancellation ++ return; ++ } ++ this.setRemainingPersistentAngerTime(event.getNewAnger()); ++ // CraftBukkit end + } + + public static boolean checkZombifiedPiglinSpawnRules( diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch deleted file mode 100644 index d726409faf..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/AbstractSkeleton.java.patch +++ /dev/null @@ -1,74 +0,0 @@ ---- a/net/minecraft/world/entity/monster/AbstractSkeleton.java -+++ b/net/minecraft/world/entity/monster/AbstractSkeleton.java -@@ -97,9 +97,15 @@ - - abstract SoundEvent getStepSound(); - -+ // Paper start - shouldBurnInDay API -+ private boolean shouldBurnInDay = true; -+ public boolean shouldBurnInDay() { return shouldBurnInDay; } -+ public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } -+ // Paper end - shouldBurnInDay API -+ - @Override - public void aiStep() { -- boolean flag = this.isSunBurnTick(); -+ boolean flag = shouldBurnInDay && this.isSunBurnTick(); // Paper - shouldBurnInDay API - - if (flag) { - ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD); -@@ -152,7 +158,7 @@ - this.populateDefaultEquipmentSlots(randomsource, difficulty); - this.populateDefaultEquipmentEnchantments(world, randomsource, difficulty); - this.reassessWeaponGoal(); -- this.setCanPickUpLoot(randomsource.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); -+ this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.skeletons || randomsource.nextFloat() < 0.55F * difficulty.getSpecialMultiplier()); // Paper - Add world settings for mobs picking up loot - if (this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) { - LocalDate localdate = LocalDate.now(); - int i = localdate.get(ChronoField.DAY_OF_MONTH); -@@ -209,7 +215,17 @@ - Level world = this.level(); - - if (world instanceof ServerLevel worldserver) { -- Projectile.spawnProjectileUsingShoot(entityarrow, worldserver, itemstack1, d0, d1 + d3 * 0.20000000298023224D, d2, 1.6F, (float) (14 - worldserver.getDifficulty().getId() * 4)); -+ // CraftBukkit start -+ org.bukkit.event.entity.EntityShootBowEvent event = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityShootBowEvent(this, this.getMainHandItem(), entityarrow.getPickupItem(), entityarrow, net.minecraft.world.InteractionHand.MAIN_HAND, 0.8F, true); // Paper - improve entity shhot bow event - add arrow stack to event -+ if (event.isCancelled()) { -+ event.getProjectile().remove(); -+ return; -+ } -+ -+ if (event.getProjectile() == entityarrow.getBukkitEntity()) { -+ Projectile.spawnProjectileUsingShoot(entityarrow, worldserver, itemstack1, d0, d1 + d3 * 0.20000000298023224D, d2, 1.6F, (float) (14 - worldserver.getDifficulty().getId() * 4)); -+ } -+ // CraftBukkit end - } - - this.playSound(SoundEvents.SKELETON_SHOOT, 1.0F, 1.0F / (this.getRandom().nextFloat() * 0.4F + 0.8F)); -@@ -233,11 +249,24 @@ - public void readAdditionalSaveData(CompoundTag nbt) { - super.readAdditionalSaveData(nbt); - this.reassessWeaponGoal(); -+ // Paper start - shouldBurnInDay API -+ if (nbt.contains("Paper.ShouldBurnInDay")) { -+ this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay"); -+ } -+ // Paper end - shouldBurnInDay API - } - -+ // Paper start - shouldBurnInDay API - @Override -- public void setItemSlot(EquipmentSlot slot, ItemStack stack) { -- super.setItemSlot(slot, stack); -+ public void addAdditionalSaveData(CompoundTag nbt) { -+ super.addAdditionalSaveData(nbt); -+ nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); -+ } -+ // Paper end - shouldBurnInDay API -+ -+ @Override -+ public void setItemSlot(EquipmentSlot slot, ItemStack stack, boolean silent) { // Paper - Fix silent equipment change -+ super.setItemSlot(slot, stack, silent); // Paper - Fix silent equipment change - if (!this.level().isClientSide) { - this.reassessWeaponGoal(); - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/CaveSpider.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/CaveSpider.java.patch deleted file mode 100644 index c2449e2257..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/CaveSpider.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/world/entity/monster/CaveSpider.java -+++ b/net/minecraft/world/entity/monster/CaveSpider.java -@@ -40,7 +40,7 @@ - } - - if (b0 > 0) { -- ((LivingEntity) target).addEffect(new MobEffectInstance(MobEffects.POISON, b0 * 20, 0), this); -+ ((LivingEntity) target).addEffect(new MobEffectInstance(MobEffects.POISON, b0 * 20, 0), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit - } - } - diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Creeper.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Creeper.java.patch deleted file mode 100644 index ea4e74957f..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Creeper.java.patch +++ /dev/null @@ -1,132 +0,0 @@ ---- a/net/minecraft/world/entity/monster/Creeper.java -+++ b/net/minecraft/world/entity/monster/Creeper.java -@@ -42,6 +42,13 @@ - import net.minecraft.world.level.Level; - import net.minecraft.world.level.gameevent.GameEvent; - -+// CraftBukkit start; -+import org.bukkit.event.entity.CreatureSpawnEvent; -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+import org.bukkit.event.entity.EntityRemoveEvent; -+import org.bukkit.event.entity.ExplosionPrimeEvent; -+// CraftBukkit end -+ - public class Creeper extends Monster { - - private static final EntityDataAccessor DATA_SWELL_DIR = SynchedEntityData.defineId(Creeper.class, EntityDataSerializers.INT); -@@ -52,6 +59,7 @@ - public int maxSwell = 30; - public int explosionRadius = 3; - private int droppedSkulls; -+ public Entity entityIgniter; // CraftBukkit - - public Creeper(EntityType type, Level world) { - super(type, world); -@@ -125,7 +133,7 @@ - } - - if (nbt.getBoolean("ignited")) { -- this.ignite(); -+ this.entityData.set(Creeper.DATA_IS_IGNITED, true); // Paper - set directly to avoid firing event - } - - } -@@ -214,9 +222,20 @@ - @Override - public void thunderHit(ServerLevel world, LightningBolt lightning) { - super.thunderHit(world, lightning); -+ // CraftBukkit start -+ if (CraftEventFactory.callCreeperPowerEvent(this, lightning, org.bukkit.event.entity.CreeperPowerEvent.PowerCause.LIGHTNING).isCancelled()) { -+ return; -+ } -+ // CraftBukkit end - this.entityData.set(Creeper.DATA_IS_POWERED, true); - } - -+ // CraftBukkit start -+ public void setPowered(boolean powered) { -+ this.entityData.set(Creeper.DATA_IS_POWERED, powered); -+ } -+ // CraftBukkit end -+ - @Override - protected InteractionResult mobInteract(Player player, InteractionHand hand) { - ItemStack itemstack = player.getItemInHand(hand); -@@ -226,8 +245,9 @@ - - this.level().playSound(player, this.getX(), this.getY(), this.getZ(), soundeffect, this.getSoundSource(), 1.0F, this.random.nextFloat() * 0.4F + 0.8F); - if (!this.level().isClientSide) { -+ this.entityIgniter = player; // CraftBukkit - this.ignite(); -- if (!itemstack.isDamageableItem()) { -+ if (itemstack.getMaxDamage() == 0) { // CraftBukkit - fix MC-264285: unbreakable flint and steels are completely consumed when igniting a creeper - itemstack.shrink(1); - } else { - itemstack.hurtAndBreak(1, player, getSlotForHand(hand)); -@@ -246,11 +266,21 @@ - if (world instanceof ServerLevel worldserver) { - float f = this.isPowered() ? 2.0F : 1.0F; - -+ // CraftBukkit start -+ ExplosionPrimeEvent event = CraftEventFactory.callExplosionPrimeEvent(this, this.explosionRadius * f, false); -+ if (!event.isCancelled()) { -+ // CraftBukkit end - this.dead = true; -- worldserver.explode(this, this.getX(), this.getY(), this.getZ(), (float) this.explosionRadius * f, Level.ExplosionInteraction.MOB); -+ worldserver.explode(this, this.getX(), this.getY(), this.getZ(), event.getRadius(), event.getFire(), Level.ExplosionInteraction.MOB); // CraftBukkit // Paper - fix DamageSource API (revert to vanilla, no, just no, don't change this) - this.spawnLingeringCloud(); - this.triggerOnDeathMobEffects(worldserver, Entity.RemovalReason.KILLED); -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.EXPLODE); // CraftBukkit - add Bukkit remove cause -+ // CraftBukkit start -+ } else { -+ this.swell = 0; -+ this.entityData.set(DATA_IS_IGNITED, Boolean.valueOf(false)); // Paper -+ } -+ // CraftBukkit end - } - - } -@@ -258,9 +288,10 @@ - private void spawnLingeringCloud() { - Collection collection = this.getActiveEffects(); - -- if (!collection.isEmpty()) { -+ if (!collection.isEmpty() && !this.level().paperConfig().entities.behavior.disableCreeperLingeringEffect) { // Paper - Option to disable creeper lingering effect - AreaEffectCloud entityareaeffectcloud = new AreaEffectCloud(this.level(), this.getX(), this.getY(), this.getZ()); - -+ entityareaeffectcloud.setOwner(this); // CraftBukkit - entityareaeffectcloud.setRadius(2.5F); - entityareaeffectcloud.setRadiusOnUse(-0.5F); - entityareaeffectcloud.setWaitTime(10); -@@ -274,7 +305,7 @@ - entityareaeffectcloud.addEffect(new MobEffectInstance(mobeffect)); - } - -- this.level().addFreshEntity(entityareaeffectcloud); -+ this.level().addFreshEntity(entityareaeffectcloud, CreatureSpawnEvent.SpawnReason.EXPLOSION); // CraftBukkit - } - - } -@@ -284,9 +315,20 @@ - } - - public void ignite() { -- this.entityData.set(Creeper.DATA_IS_IGNITED, true); -+ // Paper start - CreeperIgniteEvent -+ setIgnited(true); - } - -+ public void setIgnited(boolean ignited) { -+ if (isIgnited() != ignited) { -+ com.destroystokyo.paper.event.entity.CreeperIgniteEvent event = new com.destroystokyo.paper.event.entity.CreeperIgniteEvent((org.bukkit.entity.Creeper) getBukkitEntity(), ignited); -+ if (event.callEvent()) { -+ this.entityData.set(Creeper.DATA_IS_IGNITED, event.isIgnited()); -+ } -+ } -+ // Paper end - CreeperIgniteEvent -+ } -+ - public boolean canDropMobsSkull() { - return this.isPowered() && this.droppedSkulls < 1; - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/ElderGuardian.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/ElderGuardian.java.patch deleted file mode 100644 index b270c246e4..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/ElderGuardian.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/world/entity/monster/ElderGuardian.java -+++ b/net/minecraft/world/entity/monster/ElderGuardian.java -@@ -67,7 +67,7 @@ - super.customServerAiStep(world); - if ((this.tickCount + this.getId()) % 1200 == 0) { - MobEffectInstance mobeffect = new MobEffectInstance(MobEffects.DIG_SLOWDOWN, 6000, 2); -- List list = MobEffectUtil.addEffectToPlayersAround(world, this, this.position(), 50.0D, mobeffect, 1200); -+ List list = MobEffectUtil.addEffectToPlayersAround(world, this, this.position(), 50.0D, mobeffect, 1200, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK, (player) -> new io.papermc.paper.event.entity.ElderGuardianAppearanceEvent((org.bukkit.entity.ElderGuardian) this.getBukkitEntity(), player.getBukkitEntity()).callEvent()); // CraftBukkit // Paper - Add ElderGuardianAppearanceEvent - - list.forEach((entityplayer) -> { - entityplayer.connection.send(new ClientboundGameEventPacket(ClientboundGameEventPacket.GUARDIAN_ELDER_EFFECT, this.isSilent() ? 0.0F : 1.0F)); diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/EnderMan.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/EnderMan.java.patch deleted file mode 100644 index 512e3e45cf..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/EnderMan.java.patch +++ /dev/null @@ -1,157 +0,0 @@ ---- a/net/minecraft/world/entity/monster/EnderMan.java -+++ b/net/minecraft/world/entity/monster/EnderMan.java -@@ -68,6 +68,10 @@ - import net.minecraft.world.phys.AABB; - import net.minecraft.world.phys.BlockHitResult; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start; -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+import org.bukkit.event.entity.EntityTargetEvent; -+// CraftBukkit end - - public class EnderMan extends Monster implements NeutralMob { - -@@ -112,10 +116,26 @@ - - @Override - public void setTarget(@Nullable LivingEntity target) { -- super.setTarget(target); -+ // CraftBukkit start - fire event -+ this.setTarget(target, EntityTargetEvent.TargetReason.UNKNOWN, true); -+ } -+ -+ // Paper start - EndermanEscapeEvent -+ private boolean tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason reason) { -+ return new com.destroystokyo.paper.event.entity.EndermanEscapeEvent((org.bukkit.craftbukkit.entity.CraftEnderman) this.getBukkitEntity(), reason).callEvent(); -+ } -+ // Paper end - EndermanEscapeEvent -+ -+ @Override -+ public boolean setTarget(LivingEntity entityliving, EntityTargetEvent.TargetReason reason, boolean fireEvent) { -+ if (!super.setTarget(entityliving, reason, fireEvent)) { -+ return false; -+ } -+ entityliving = this.getTarget(); -+ // CraftBukkit end - AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED); - -- if (target == null) { -+ if (entityliving == null) { - this.targetChangeTime = 0; - this.entityData.set(EnderMan.DATA_CREEPY, false); - this.entityData.set(EnderMan.DATA_STARED_AT, false); -@@ -127,6 +147,7 @@ - attributemodifiable.addTransientModifier(EnderMan.SPEED_MODIFIER_ATTACKING); - } - } -+ return true; - - } - -@@ -212,6 +233,14 @@ - } - - boolean isBeingStaredBy(Player player) { -+ // Paper start - EndermanAttackPlayerEvent -+ final boolean shouldAttack = isBeingStaredBy0(player); -+ final com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent event = new com.destroystokyo.paper.event.entity.EndermanAttackPlayerEvent((org.bukkit.entity.Enderman) getBukkitEntity(), (org.bukkit.entity.Player) player.getBukkitEntity()); -+ event.setCancelled(!shouldAttack); -+ return event.callEvent(); -+ } -+ private boolean isBeingStaredBy0(Player player) { -+ // Paper end - EndermanAttackPlayerEvent - return !LivingEntity.PLAYER_NOT_WEARING_DISGUISE_ITEM.test(player) ? false : this.isLookingAtMe(player, 0.025D, true, false, new double[]{this.getEyeY()}); - } - -@@ -241,7 +270,7 @@ - if (world.isDay() && this.tickCount >= this.targetChangeTime + 600) { - float f = this.getLightLevelDependentMagicValue(); - -- if (f > 0.5F && world.canSeeSky(this.blockPosition()) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F) { -+ if (f > 0.5F && world.canSeeSky(this.blockPosition()) && this.random.nextFloat() * 30.0F < (f - 0.4F) * 2.0F && this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.RUNAWAY)) { // Paper - EndermanEscapeEvent - this.setTarget((LivingEntity) null); - this.teleport(); - } -@@ -367,11 +396,13 @@ - } else { - flag1 = flag && this.hurtWithCleanWater(world, source, (ThrownPotion) source.getDirectEntity(), amount); - -+ if (this.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.INDIRECT)) { // Paper - EndermanEscapeEvent - for (int i = 0; i < 64; ++i) { - if (this.teleport()) { - return true; - } - } -+ } // Paper - EndermanEscapeEvent - - return flag1; - } -@@ -397,6 +428,16 @@ - this.entityData.set(EnderMan.DATA_STARED_AT, true); - } - -+ // Paper start -+ public void setCreepy(boolean creepy) { -+ this.entityData.set(EnderMan.DATA_CREEPY, creepy); -+ } -+ -+ public void setHasBeenStaredAt(boolean hasBeenStaredAt) { -+ this.entityData.set(EnderMan.DATA_STARED_AT, hasBeenStaredAt); -+ } -+ // Paper end -+ - @Override - public boolean requiresCustomPersistence() { - return super.requiresCustomPersistence() || this.getCarriedBlock() != null; -@@ -457,7 +498,8 @@ - int j = Mth.floor(this.enderman.getY() + randomsource.nextDouble() * 2.0D); - int k = Mth.floor(this.enderman.getZ() - 1.0D + randomsource.nextDouble() * 2.0D); - BlockPos blockposition = new BlockPos(i, j, k); -- BlockState iblockdata = world.getBlockState(blockposition); -+ BlockState iblockdata = world.getBlockStateIfLoaded(blockposition); // Paper - Prevent endermen from loading chunks -+ if (iblockdata == null) return; // Paper - Prevent endermen from loading chunks - BlockPos blockposition1 = blockposition.below(); - BlockState iblockdata1 = world.getBlockState(blockposition1); - BlockState iblockdata2 = this.enderman.getCarriedBlock(); -@@ -465,9 +507,11 @@ - if (iblockdata2 != null) { - iblockdata2 = Block.updateFromNeighbourShapes(iblockdata2, this.enderman.level(), blockposition); - if (this.canPlaceBlock(world, blockposition, iblockdata2, iblockdata, iblockdata1, blockposition1)) { -+ if (CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockposition, iblockdata2)) { // CraftBukkit - Place event - world.setBlock(blockposition, iblockdata2, 3); - world.gameEvent((Holder) GameEvent.BLOCK_PLACE, blockposition, GameEvent.Context.of(this.enderman, iblockdata2)); - this.enderman.setCarriedBlock((BlockState) null); -+ } // CraftBukkit - } - - } -@@ -499,16 +543,19 @@ - int j = Mth.floor(this.enderman.getY() + randomsource.nextDouble() * 3.0D); - int k = Mth.floor(this.enderman.getZ() - 2.0D + randomsource.nextDouble() * 4.0D); - BlockPos blockposition = new BlockPos(i, j, k); -- BlockState iblockdata = world.getBlockState(blockposition); -+ BlockState iblockdata = world.getBlockStateIfLoaded(blockposition); // Paper - Prevent endermen from loading chunks -+ if (iblockdata == null) return; // Paper - Prevent endermen from loading chunks - Vec3 vec3d = new Vec3((double) this.enderman.getBlockX() + 0.5D, (double) j + 0.5D, (double) this.enderman.getBlockZ() + 0.5D); - Vec3 vec3d1 = new Vec3((double) i + 0.5D, (double) j + 0.5D, (double) k + 0.5D); - BlockHitResult movingobjectpositionblock = world.clip(new ClipContext(vec3d, vec3d1, ClipContext.Block.OUTLINE, ClipContext.Fluid.NONE, this.enderman)); - boolean flag = movingobjectpositionblock.getBlockPos().equals(blockposition); - - if (iblockdata.is(BlockTags.ENDERMAN_HOLDABLE) && flag) { -+ if (CraftEventFactory.callEntityChangeBlockEvent(this.enderman, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // CraftBukkit - Place event // Paper - fix wrong block state - world.removeBlock(blockposition, false); - world.gameEvent((Holder) GameEvent.BLOCK_DESTROY, blockposition, GameEvent.Context.of(this.enderman, iblockdata)); - this.enderman.setCarriedBlock(iblockdata.getBlock().defaultBlockState()); -+ } // CraftBukkit - } - - } -@@ -592,7 +639,7 @@ - } else { - if (this.target != null && !this.enderman.isPassenger()) { - if (this.enderman.isBeingStaredBy((Player) this.target)) { -- if (this.target.distanceToSqr((Entity) this.enderman) < 16.0D) { -+ if (this.target.distanceToSqr((Entity) this.enderman) < 16.0D && this.enderman.tryEscape(com.destroystokyo.paper.event.entity.EndermanEscapeEvent.Reason.STARE)) { // Paper - EndermanEscapeEvent - this.enderman.teleport(); - } - diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Endermite.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Endermite.java.patch deleted file mode 100644 index 9a32ade2bd..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Endermite.java.patch +++ /dev/null @@ -1,21 +0,0 @@ ---- a/net/minecraft/world/entity/monster/Endermite.java -+++ b/net/minecraft/world/entity/monster/Endermite.java -@@ -24,6 +24,9 @@ - import net.minecraft.world.level.Level; - import net.minecraft.world.level.LevelAccessor; - import net.minecraft.world.level.block.state.BlockState; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class Endermite extends Monster { - -@@ -113,7 +116,7 @@ - } - - if (this.life >= 2400) { -- this.discard(); -+ this.discard(EntityRemoveEvent.Cause.DESPAWN); // CraftBukkit - add Bukkit remove cause - } - } - diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Evoker.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Evoker.java.patch deleted file mode 100644 index d8921518a6..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Evoker.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/world/entity/monster/Evoker.java -+++ b/net/minecraft/world/entity/monster/Evoker.java -@@ -212,7 +212,7 @@ - worldserver.getScoreboard().addPlayerToTeam(entityvex.getScoreboardName(), scoreboardteam); - } - -- worldserver.addFreshEntityWithPassengers(entityvex); -+ worldserver.addFreshEntityWithPassengers(entityvex, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SPELL); // CraftBukkit - Add SpawnReason - worldserver.gameEvent((Holder) GameEvent.ENTITY_PLACE, blockposition, GameEvent.Context.of((Entity) Evoker.this)); - } - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Ghast.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Ghast.java.patch deleted file mode 100644 index e91f483915..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Ghast.java.patch +++ /dev/null @@ -1,25 +0,0 @@ ---- a/net/minecraft/world/entity/monster/Ghast.java -+++ b/net/minecraft/world/entity/monster/Ghast.java -@@ -64,7 +64,13 @@ - - public int getExplosionPower() { - return this.explosionPower; -+ } -+ -+ // Paper start -+ public void setExplosionPower(int explosionPower) { -+ this.explosionPower = explosionPower; - } -+ // Paper end - - @Override - protected boolean shouldDespawnInPeaceful() { -@@ -333,6 +339,8 @@ - - LargeFireball entitylargefireball = new LargeFireball(world, this.ghast, vec3d1.normalize(), this.ghast.getExplosionPower()); - -+ // CraftBukkit - set bukkitYield when setting explosionpower -+ entitylargefireball.bukkitYield = entitylargefireball.explosionPower = this.ghast.getExplosionPower(); - entitylargefireball.setPos(this.ghast.getX() + vec3d.x * 4.0D, this.ghast.getY(0.5D) + 0.5D, entitylargefireball.getZ() + vec3d.z * 4.0D); - world.addFreshEntity(entitylargefireball); - this.chargeTime = -40; diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Husk.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Husk.java.patch deleted file mode 100644 index 0df55d8f37..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Husk.java.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/net/minecraft/world/entity/monster/Husk.java -+++ b/net/minecraft/world/entity/monster/Husk.java -@@ -59,7 +59,7 @@ - if (flag && this.getMainHandItem().isEmpty() && target instanceof LivingEntity) { - float f = this.level().getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty(); - -- ((LivingEntity) target).addEffect(new MobEffectInstance(MobEffects.HUNGER, 140 * (int) f), this); -+ ((LivingEntity) target).addEffect(new MobEffectInstance(MobEffects.HUNGER, 140 * (int) f), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit - } - - return flag; diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Phantom.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Phantom.java.patch deleted file mode 100644 index ca42f84c2e..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Phantom.java.patch +++ /dev/null @@ -1,78 +0,0 @@ ---- a/net/minecraft/world/entity/monster/Phantom.java -+++ b/net/minecraft/world/entity/monster/Phantom.java -@@ -139,7 +139,7 @@ - - @Override - public void aiStep() { -- if (this.isAlive() && this.isSunBurnTick()) { -+ if (this.isAlive() && this.shouldBurnInDay && this.isSunBurnTick()) { // Paper - shouldBurnInDay API - this.igniteForSeconds(8.0F); - } - -@@ -161,6 +161,14 @@ - } - - this.setPhantomSize(nbt.getInt("Size")); -+ // Paper start -+ if (nbt.hasUUID("Paper.SpawningEntity")) { -+ this.spawningEntity = nbt.getUUID("Paper.SpawningEntity"); -+ } -+ if (nbt.contains("Paper.ShouldBurnInDay")) { -+ this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay"); -+ } -+ // Paper end - } - - @Override -@@ -170,6 +178,12 @@ - nbt.putInt("AY", this.anchorPoint.getY()); - nbt.putInt("AZ", this.anchorPoint.getZ()); - nbt.putInt("Size", this.getPhantomSize()); -+ // Paper start -+ if (this.spawningEntity != null) { -+ nbt.putUUID("Paper.SpawningEntity", this.spawningEntity); -+ } -+ nbt.putBoolean("Paper.ShouldBurnInDay", shouldBurnInDay); -+ // Paper end - } - - @Override -@@ -219,6 +233,20 @@ - return predicate.test(world, this, target); - } - -+ // Paper start -+ @Nullable -+ java.util.UUID spawningEntity; -+ -+ @Nullable -+ public java.util.UUID getSpawningEntity() { -+ return this.spawningEntity; -+ } -+ public void setSpawningEntity(java.util.UUID entity) { this.spawningEntity = entity; } -+ private boolean shouldBurnInDay = true; -+ public boolean shouldBurnInDay() { return shouldBurnInDay; } -+ public void setShouldBurnInDay(boolean shouldBurnInDay) { this.shouldBurnInDay = shouldBurnInDay; } -+ // Paper end -+ - private static enum AttackPhase { - - CIRCLE, SWOOP; -@@ -522,14 +550,15 @@ - List list = worldserver.getNearbyPlayers(this.attackTargeting, Phantom.this, Phantom.this.getBoundingBox().inflate(16.0D, 64.0D, 16.0D)); - - if (!list.isEmpty()) { -- list.sort(Comparator.comparing(Entity::getY).reversed()); -+ list.sort(Comparator.comparing((Entity e) -> { return e.getY(); }).reversed()); // CraftBukkit - decompile error - Iterator iterator = list.iterator(); - - while (iterator.hasNext()) { - Player entityhuman = (Player) iterator.next(); - - if (Phantom.this.canAttack(worldserver, entityhuman, TargetingConditions.DEFAULT)) { -- Phantom.this.setTarget(entityhuman); -+ if (!level().paperConfig().entities.behavior.phantomsOnlyAttackInsomniacs || EntitySelector.IS_INSOMNIAC.test(entityhuman)) // Paper - Add phantom creative and insomniac controls -+ Phantom.this.setTarget(entityhuman, org.bukkit.event.entity.EntityTargetEvent.TargetReason.CLOSEST_PLAYER, true); // CraftBukkit - reason - return true; - } - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Pillager.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Pillager.java.patch deleted file mode 100644 index 43bd8b72e6..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Pillager.java.patch +++ /dev/null @@ -1,21 +0,0 @@ ---- a/net/minecraft/world/entity/monster/Pillager.java -+++ b/net/minecraft/world/entity/monster/Pillager.java -@@ -52,6 +52,9 @@ - import net.minecraft.world.level.Level; - import net.minecraft.world.level.LevelReader; - import net.minecraft.world.level.ServerLevelAccessor; -+// CraftBukkit start -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class Pillager extends AbstractIllager implements CrossbowAttackMob, InventoryCarrier { - -@@ -206,7 +209,7 @@ - ItemStack itemstack1 = this.inventory.addItem(itemstack); - - if (itemstack1.isEmpty()) { -- itemEntity.discard(); -+ itemEntity.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause - } else { - itemstack.setCount(itemstack1.getCount()); - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Ravager.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Ravager.java.patch deleted file mode 100644 index 1cbab8cd90..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Ravager.java.patch +++ /dev/null @@ -1,41 +0,0 @@ ---- a/net/minecraft/world/entity/monster/Ravager.java -+++ b/net/minecraft/world/entity/monster/Ravager.java -@@ -42,6 +42,9 @@ - import net.minecraft.world.level.pathfinder.PathType; - import net.minecraft.world.phys.AABB; - import net.minecraft.world.phys.Vec3; -+// CraftBukkit start -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+// CraftBukkit end - - public class Ravager extends Raider { - -@@ -158,12 +161,19 @@ - Block block = iblockdata.getBlock(); - - if (block instanceof LeavesBlock) { -+ // CraftBukkit start -+ if (!CraftEventFactory.callEntityChangeBlockEvent(this, blockposition, iblockdata.getFluidState().createLegacyBlock())) { // Paper - fix wrong block state -+ continue; -+ } -+ // CraftBukkit end - flag = worldserver.destroyBlock(blockposition, true, this) || flag; - } - } - - if (!flag && this.onGround()) { -+ if (new com.destroystokyo.paper.event.entity.EntityJumpEvent(getBukkitLivingEntity()).callEvent()) { // Paper - Entity Jump API - this.jumpFromGround(); -+ } else { this.setJumping(false); } // Paper - Entity Jump API; setJumping(false) stops a potential loop - } - } - } -@@ -281,7 +291,7 @@ - double d1 = entity.getZ() - this.getZ(); - double d2 = Math.max(d0 * d0 + d1 * d1, 0.001D); - -- entity.push(d0 / d2 * 4.0D, 0.2D, d1 / d2 * 4.0D); -+ entity.push(d0 / d2 * 4.0D, 0.2D, d1 / d2 * 4.0D, this); // Paper - Add EntityKnockbackByEntityEvent and EntityPushedByEntityAttackEvent - } - - @Override diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Shulker.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Shulker.java.patch deleted file mode 100644 index fb73125321..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Shulker.java.patch +++ /dev/null @@ -1,59 +0,0 @@ ---- a/net/minecraft/world/entity/monster/Shulker.java -+++ b/net/minecraft/world/entity/monster/Shulker.java -@@ -59,6 +59,12 @@ - import net.minecraft.world.phys.Vec3; - import org.joml.Vector3f; - -+// CraftBukkit start -+import org.bukkit.craftbukkit.util.CraftLocation; -+import org.bukkit.event.entity.EntityTeleportEvent; -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+// CraftBukkit end -+ - public class Shulker extends AbstractGolem implements VariantHolder>, Enemy { - - private static final ResourceLocation COVERED_ARMOR_MODIFIER_ID = ResourceLocation.withDefaultNamespace("covered"); -@@ -283,7 +289,13 @@ - - @Override - public void stopRiding() { -- super.stopRiding(); -+ // Paper start - Force entity dismount during teleportation -+ this.stopRiding(false); -+ } -+ @Override -+ public void stopRiding(boolean suppressCancellation) { -+ super.stopRiding(suppressCancellation); -+ // Paper end - Force entity dismount during teleportation - if (this.level().isClientSide) { - this.clientOldAttachPosition = this.blockPosition(); - } -@@ -402,6 +414,14 @@ - Direction enumdirection = this.findAttachableSurface(blockposition1); - - if (enumdirection != null) { -+ // CraftBukkit start -+ EntityTeleportEvent teleportEvent = CraftEventFactory.callEntityTeleportEvent(this, blockposition1.getX(), blockposition1.getY(), blockposition1.getZ()); -+ if (teleportEvent.isCancelled() || teleportEvent.getTo() == null) { // Paper -+ return false; -+ } else { -+ blockposition1 = CraftLocation.toBlockPosition(teleportEvent.getTo()); -+ } -+ // CraftBukkit end - this.unRide(); - this.setAttachFace(enumdirection); - this.playSound(SoundEvents.SHULKER_TELEPORT, 1.0F, 1.0F); -@@ -472,7 +492,12 @@ - if (entityshulker != null) { - entityshulker.setVariant(this.getVariant()); - entityshulker.moveTo(vec3d); -- this.level().addFreshEntity(entityshulker); -+ // Paper start - Shulker duplicate event -+ if (!new io.papermc.paper.event.entity.ShulkerDuplicateEvent((org.bukkit.entity.Shulker) entityshulker.getBukkitEntity(), (org.bukkit.entity.Shulker) this.getBukkitEntity()).callEvent()) { -+ return; -+ } -+ // Paper end - Shulker duplicate event -+ this.level().addFreshEntity(entityshulker, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - the mysteries of life - } - - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Silverfish.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Silverfish.java.patch deleted file mode 100644 index b031571b09..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Silverfish.java.patch +++ /dev/null @@ -1,51 +0,0 @@ ---- a/net/minecraft/world/entity/monster/Silverfish.java -+++ b/net/minecraft/world/entity/monster/Silverfish.java -@@ -30,6 +30,10 @@ - import net.minecraft.world.level.block.Block; - import net.minecraft.world.level.block.InfestedBlock; - import net.minecraft.world.level.block.state.BlockState; -+// CraftBukkit start -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+import org.bukkit.event.entity.EntityRemoveEvent; -+// CraftBukkit end - - public class Silverfish extends Monster { - -@@ -119,7 +123,7 @@ - } else { - Player entityhuman = world.getNearestPlayer((double) pos.getX() + 0.5D, (double) pos.getY() + 0.5D, (double) pos.getZ() + 0.5D, 5.0D, true); - -- return entityhuman == null; -+ return !(entityhuman != null && !entityhuman.affectsSpawning) && entityhuman == null; // Paper - Affects Spawning API - } - } - -@@ -160,6 +164,12 @@ - Block block = iblockdata.getBlock(); - - if (block instanceof InfestedBlock) { -+ // CraftBukkit start -+ BlockState afterState = getServerLevel(world).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING) ? iblockdata.getFluidState().createLegacyBlock() : ((InfestedBlock) block).hostStateByInfested(world.getBlockState(blockposition1)); // Paper - fix wrong block state -+ if (!CraftEventFactory.callEntityChangeBlockEvent(this.silverfish, blockposition1, afterState)) { // Paper - fix wrong block state -+ continue; -+ } -+ // CraftBukkit end - if (getServerLevel(world).getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) { - world.destroyBlock(blockposition1, true, this.silverfish); - } else { -@@ -229,9 +239,14 @@ - BlockState iblockdata = world.getBlockState(blockposition); - - if (InfestedBlock.isCompatibleHostBlock(iblockdata)) { -+ // CraftBukkit start -+ if (!CraftEventFactory.callEntityChangeBlockEvent(this.mob, blockposition, InfestedBlock.infestedStateByHost(iblockdata))) { -+ return; -+ } -+ // CraftBukkit end - world.setBlock(blockposition, InfestedBlock.infestedStateByHost(iblockdata), 3); - this.mob.spawnAnim(); -- this.mob.discard(); -+ this.mob.discard(EntityRemoveEvent.Cause.ENTER_BLOCK); // CraftBukkit - add Bukkit remove cause - } - - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Slime.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Slime.java.patch deleted file mode 100644 index 4ee5279ca5..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Slime.java.patch +++ /dev/null @@ -1,239 +0,0 @@ ---- a/net/minecraft/world/entity/monster/Slime.java -+++ b/net/minecraft/world/entity/monster/Slime.java -@@ -46,6 +46,14 @@ - import net.minecraft.world.level.levelgen.WorldgenRandom; - import net.minecraft.world.phys.Vec3; - import net.minecraft.world.scores.PlayerTeam; -+// CraftBukkit start -+import java.util.ArrayList; -+import java.util.List; -+import org.bukkit.craftbukkit.event.CraftEventFactory; -+import org.bukkit.event.entity.EntityRemoveEvent; -+import org.bukkit.event.entity.EntityTransformEvent; -+import org.bukkit.event.entity.SlimeSplitEvent; -+// CraftBukkit end - - public class Slime extends Mob implements Enemy { - -@@ -111,6 +119,7 @@ - @Override - public void addAdditionalSaveData(CompoundTag nbt) { - super.addAdditionalSaveData(nbt); -+ nbt.putBoolean("Paper.canWander", this.canWander); // Paper - nbt.putInt("Size", this.getSize() - 1); - nbt.putBoolean("wasOnGround", this.wasOnGround); - } -@@ -119,6 +128,11 @@ - public void readAdditionalSaveData(CompoundTag nbt) { - this.setSize(nbt.getInt("Size") + 1, false); - super.readAdditionalSaveData(nbt); -+ // Paper start -+ if (nbt.contains("Paper.canWander")) { -+ this.canWander = nbt.getBoolean("Paper.canWander"); -+ } -+ // Paper end - this.wasOnGround = nbt.getBoolean("wasOnGround"); - } - -@@ -197,11 +211,18 @@ - - @Override - public EntityType getType() { -- return super.getType(); -+ return (EntityType) super.getType(); // CraftBukkit - decompile error - } - - @Override - public void remove(Entity.RemovalReason reason) { -+ // CraftBukkit start - add Bukkit remove cause -+ this.remove(reason, null); -+ } -+ -+ @Override -+ public void remove(Entity.RemovalReason entity_removalreason, EntityRemoveEvent.Cause cause) { -+ // CraftBukkit end - int i = this.getSize(); - - if (!this.level().isClientSide && i > 1 && this.isDeadOrDying()) { -@@ -210,19 +231,47 @@ - int j = i / 2; - int k = 2 + this.random.nextInt(3); - PlayerTeam scoreboardteam = this.getTeam(); -+ -+ // CraftBukkit start -+ SlimeSplitEvent event = new SlimeSplitEvent((org.bukkit.entity.Slime) this.getBukkitEntity(), k); -+ this.level().getCraftServer().getPluginManager().callEvent(event); -+ -+ if (!event.isCancelled() && event.getCount() > 0) { -+ k = event.getCount(); -+ } else { -+ super.remove(entity_removalreason, cause); // CraftBukkit - add Bukkit remove cause -+ return; -+ } -+ List slimes = new ArrayList<>(j); -+ // CraftBukkit end - - for (int l = 0; l < k; ++l) { - float f2 = ((float) (l % 2) - 0.5F) * f1; - float f3 = ((float) (l / 2) - 0.5F) * f1; - -- this.convertTo(this.getType(), new ConversionParams(ConversionType.SPLIT_ON_DEATH, false, false, scoreboardteam), EntitySpawnReason.TRIGGERED, (entityslime) -> { -+ Slime converted = this.convertTo(this.getType(), new ConversionParams(ConversionType.SPLIT_ON_DEATH, false, false, scoreboardteam), EntitySpawnReason.TRIGGERED, (entityslime) -> { // CraftBukkit -+ entityslime.aware = this.aware; // Paper - Fix nerfed slime when splitting - entityslime.setSize(j, true); - entityslime.moveTo(this.getX() + (double) f2, this.getY() + 0.5D, this.getZ() + (double) f3, this.random.nextFloat() * 360.0F, 0.0F); -- }); -+ // CraftBukkit start -+ }, null, null); -+ if (converted != null) { -+ slimes.add(converted); -+ } -+ // CraftBukkit end - } -+ // CraftBukkit start -+ if (CraftEventFactory.callEntityTransformEvent(this, slimes, EntityTransformEvent.TransformReason.SPLIT).isCancelled()) { -+ super.remove(entity_removalreason, cause); // CraftBukkit - add Bukkit remove cause -+ return; -+ } -+ for (LivingEntity living : slimes) { -+ this.level().addFreshEntity(living, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.SLIME_SPLIT); // CraftBukkit - SpawnReason -+ } -+ // CraftBukkit end - } - -- super.remove(reason); -+ super.remove(entity_removalreason, cause); // CraftBukkit - add Bukkit remove cause - } - - @Override -@@ -291,7 +340,11 @@ - return checkMobSpawnRules(type, world, spawnReason, pos, random); - } - -- if (world.getBiome(pos).is(BiomeTags.ALLOWS_SURFACE_SLIME_SPAWNS) && pos.getY() > 50 && pos.getY() < 70 && random.nextFloat() < 0.5F && random.nextFloat() < world.getMoonBrightness() && world.getMaxLocalRawBrightness(pos) <= random.nextInt(8)) { -+ // Paper start - Replace rules for Height in Swamp Biome -+ final double maxHeightSwamp = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.surfaceBiome.maximum; -+ final double minHeightSwamp = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.surfaceBiome.minimum; -+ if (world.getBiome(pos).is(BiomeTags.ALLOWS_SURFACE_SLIME_SPAWNS) && pos.getY() > minHeightSwamp && pos.getY() < maxHeightSwamp && random.nextFloat() < 0.5F && random.nextFloat() < world.getMoonBrightness() && world.getMaxLocalRawBrightness(pos) <= random.nextInt(8)) { -+ // Paper end - Replace rules for Height in Swamp Biome - return checkMobSpawnRules(type, world, spawnReason, pos, random); - } - -@@ -300,9 +353,12 @@ - } - - ChunkPos chunkcoordintpair = new ChunkPos(pos); -- boolean flag = WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), 987234911L).nextInt(10) == 0; -+ boolean flag = world.getMinecraftWorld().paperConfig().entities.spawning.allChunksAreSlimeChunks || WorldgenRandom.seedSlimeChunk(chunkcoordintpair.x, chunkcoordintpair.z, ((WorldGenLevel) world).getSeed(), world.getMinecraftWorld().spigotConfig.slimeSeed).nextInt(10) == 0; // Spigot // Paper - -- if (random.nextInt(10) == 0 && flag && pos.getY() < 40) { -+ // Paper start - Replace rules for Height in Slime Chunks -+ final double maxHeightSlimeChunk = world.getMinecraftWorld().paperConfig().entities.spawning.slimeSpawnHeight.slimeChunk.maximum; -+ if (random.nextInt(10) == 0 && flag && pos.getY() < maxHeightSlimeChunk) { -+ // Paper end - Replace rules for Height in Slime Chunks - return checkMobSpawnRules(type, world, spawnReason, pos, random); - } - } -@@ -432,7 +488,7 @@ - - @Override - public boolean canUse() { -- return (this.slime.isInWater() || this.slime.isInLava()) && this.slime.getMoveControl() instanceof Slime.SlimeMoveControl; -+ return (this.slime.isInWater() || this.slime.isInLava()) && this.slime.getMoveControl() instanceof Slime.SlimeMoveControl && this.slime.canWander && new com.destroystokyo.paper.event.entity.SlimeSwimEvent((org.bukkit.entity.Slime) this.slime.getBukkitEntity()).callEvent(); // Paper - Slime pathfinder events - } - - @Override -@@ -469,7 +525,15 @@ - public boolean canUse() { - LivingEntity entityliving = this.slime.getTarget(); - -- return entityliving == null ? false : (!this.slime.canAttack(entityliving) ? false : this.slime.getMoveControl() instanceof Slime.SlimeMoveControl); -+ // Paper start - Slime pathfinder events -+ if (entityliving == null || !entityliving.isAlive()) { -+ return false; -+ } -+ if (!this.slime.canAttack(entityliving)) { -+ return false; -+ } -+ return this.slime.getMoveControl() instanceof Slime.SlimeMoveControl && this.slime.canWander && new com.destroystokyo.paper.event.entity.SlimeTargetLivingEntityEvent((org.bukkit.entity.Slime) this.slime.getBukkitEntity(), (org.bukkit.entity.LivingEntity) entityliving.getBukkitEntity()).callEvent(); -+ // Paper end - Slime pathfinder events - } - - @Override -@@ -482,7 +546,15 @@ - public boolean canContinueToUse() { - LivingEntity entityliving = this.slime.getTarget(); - -- return entityliving == null ? false : (!this.slime.canAttack(entityliving) ? false : --this.growTiredTimer > 0); -+ // Paper start - Slime pathfinder events -+ if (entityliving == null || !entityliving.isAlive()) { -+ return false; -+ } -+ if (!this.slime.canAttack(entityliving)) { -+ return false; -+ } -+ return --this.growTiredTimer > 0 && this.slime.canWander && new com.destroystokyo.paper.event.entity.SlimeTargetLivingEntityEvent((org.bukkit.entity.Slime) this.slime.getBukkitEntity(), (org.bukkit.entity.LivingEntity) entityliving.getBukkitEntity()).callEvent(); -+ // Paper end - Slime pathfinder events - } - - @Override -@@ -505,6 +577,13 @@ - } - - } -+ -+ // Paper start - Slime pathfinder events; clear timer and target when goal resets -+ public void stop() { -+ this.growTiredTimer = 0; -+ this.slime.setTarget(null); -+ } -+ // Paper end - Slime pathfinder events - } - - private static class SlimeRandomDirectionGoal extends Goal { -@@ -520,7 +599,7 @@ - - @Override - public boolean canUse() { -- return this.slime.getTarget() == null && (this.slime.onGround() || this.slime.isInWater() || this.slime.isInLava() || this.slime.hasEffect(MobEffects.LEVITATION)) && this.slime.getMoveControl() instanceof Slime.SlimeMoveControl; -+ return this.slime.getTarget() == null && (this.slime.onGround() || this.slime.isInWater() || this.slime.isInLava() || this.slime.hasEffect(MobEffects.LEVITATION)) && this.slime.getMoveControl() instanceof Slime.SlimeMoveControl && this.slime.canWander; // Paper - Slime pathfinder events - } - - @Override -@@ -528,6 +607,11 @@ - if (--this.nextRandomizeTime <= 0) { - this.nextRandomizeTime = this.adjustedTickDelay(40 + this.slime.getRandom().nextInt(60)); - this.chosenDegrees = (float) this.slime.getRandom().nextInt(360); -+ // Paper start - Slime pathfinder events -+ com.destroystokyo.paper.event.entity.SlimeChangeDirectionEvent event = new com.destroystokyo.paper.event.entity.SlimeChangeDirectionEvent((org.bukkit.entity.Slime) this.slime.getBukkitEntity(), this.chosenDegrees); -+ if (!this.slime.canWander || !event.callEvent()) return; -+ this.chosenDegrees = event.getNewYaw(); -+ // Paper end - Slime pathfinder events - } - - MoveControl controllermove = this.slime.getMoveControl(); -@@ -550,7 +634,7 @@ - - @Override - public boolean canUse() { -- return !this.slime.isPassenger(); -+ return !this.slime.isPassenger() && this.slime.canWander && new com.destroystokyo.paper.event.entity.SlimeWanderEvent((org.bukkit.entity.Slime) this.slime.getBukkitEntity()).callEvent(); // Paper - Slime pathfinder events - } - - @Override -@@ -563,4 +647,15 @@ - - } - } -+ -+ // Paper start - Slime pathfinder events -+ private boolean canWander = true; -+ public boolean canWander() { -+ return canWander; -+ } -+ -+ public void setWander(boolean canWander) { -+ this.canWander = canWander; -+ } -+ // Paper end - Slime pathfinder events - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/WitherSkeleton.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/WitherSkeleton.java.patch deleted file mode 100644 index 61b7e05667..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/WitherSkeleton.java.patch +++ /dev/null @@ -1,19 +0,0 @@ ---- a/net/minecraft/world/entity/monster/WitherSkeleton.java -+++ b/net/minecraft/world/entity/monster/WitherSkeleton.java -@@ -110,7 +110,7 @@ - return false; - } else { - if (target instanceof LivingEntity) { -- ((LivingEntity) target).addEffect(new MobEffectInstance(MobEffects.WITHER, 200), this); -+ ((LivingEntity) target).addEffect(new MobEffectInstance(MobEffects.WITHER, 200), this, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.ATTACK); // CraftBukkit - } - - return true; -@@ -127,6 +127,6 @@ - - @Override - public boolean canBeAffected(MobEffectInstance effect) { -- return effect.is(MobEffects.WITHER) ? false : super.canBeAffected(effect); -+ return effect.is(MobEffects.WITHER) && this.level().paperConfig().entities.mobEffects.immuneToWitherEffect.witherSkeleton ? false : super.canBeAffected(effect); // Paper - Add config for mobs immune to default effects - } - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Zombie.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Zombie.java.patch deleted file mode 100644 index 4b95368547..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/Zombie.java.patch +++ /dev/null @@ -1,304 +0,0 @@ ---- a/net/minecraft/world/entity/monster/Zombie.java -+++ b/net/minecraft/world/entity/monster/Zombie.java -@@ -6,19 +6,6 @@ - import java.util.List; - import java.util.function.Predicate; - import javax.annotation.Nullable; --import net.minecraft.core.BlockPos; --import net.minecraft.nbt.CompoundTag; --import net.minecraft.nbt.NbtOps; --import net.minecraft.nbt.Tag; --import net.minecraft.network.syncher.EntityDataAccessor; --import net.minecraft.network.syncher.EntityDataSerializers; --import net.minecraft.network.syncher.SynchedEntityData; --import net.minecraft.resources.ResourceLocation; --import net.minecraft.server.level.ServerLevel; --import net.minecraft.sounds.SoundEvent; --import net.minecraft.sounds.SoundEvents; --import net.minecraft.sounds.SoundSource; --import net.minecraft.tags.FluidTags; - import net.minecraft.util.Mth; - import net.minecraft.util.RandomSource; - import net.minecraft.world.Difficulty; -@@ -66,11 +53,31 @@ - import net.minecraft.world.level.ServerLevelAccessor; - import net.minecraft.world.level.block.Blocks; - import net.minecraft.world.level.block.state.BlockState; -+import net.minecraft.core.BlockPos; -+import net.minecraft.nbt.CompoundTag; -+import net.minecraft.nbt.NbtOps; -+import net.minecraft.nbt.Tag; -+import net.minecraft.network.syncher.EntityDataAccessor; -+import net.minecraft.network.syncher.EntityDataSerializers; -+import net.minecraft.network.syncher.SynchedEntityData; -+import net.minecraft.resources.ResourceLocation; -+// CraftBukkit start -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.sounds.SoundEvent; -+import net.minecraft.sounds.SoundEvents; -+import net.minecraft.sounds.SoundSource; -+import net.minecraft.tags.FluidTags; -+import org.bukkit.event.entity.CreatureSpawnEvent; -+import org.bukkit.event.entity.EntityCombustByEntityEvent; -+import org.bukkit.event.entity.EntityTargetEvent; -+import org.bukkit.event.entity.EntityTransformEvent; -+// CraftBukkit end - - public class Zombie extends Monster { - - private static final ResourceLocation SPEED_MODIFIER_BABY_ID = ResourceLocation.withDefaultNamespace("baby"); -- private static final AttributeModifier SPEED_MODIFIER_BABY = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_ID, 0.5D, AttributeModifier.Operation.ADD_MULTIPLIED_BASE); -+ private final AttributeModifier babyModifier = new AttributeModifier(Zombie.SPEED_MODIFIER_BABY_ID, this.level().paperConfig().entities.behavior.babyZombieMovementModifier, AttributeModifier.Operation.ADD_MULTIPLIED_BASE); // Paper - Make baby speed configurable - private static final ResourceLocation REINFORCEMENT_CALLER_CHARGE_ID = ResourceLocation.withDefaultNamespace("reinforcement_caller_charge"); - private static final AttributeModifier ZOMBIE_REINFORCEMENT_CALLEE_CHARGE = new AttributeModifier(ResourceLocation.withDefaultNamespace("reinforcement_callee_charge"), -0.05000000074505806D, AttributeModifier.Operation.ADD_VALUE); - private static final ResourceLocation LEADER_ZOMBIE_BONUS_ID = ResourceLocation.withDefaultNamespace("leader_zombie_bonus"); -@@ -91,10 +98,12 @@ - private boolean canBreakDoors; - private int inWaterTime; - public int conversionTime; -+ // private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field // Paper - remove anti tick skipping measures / wall time -+ private boolean shouldBurnInDay = true; // Paper - Add more Zombie API - - public Zombie(EntityType type, Level world) { - super(type, world); -- this.breakDoorGoal = new BreakDoorGoal(this, Zombie.DOOR_BREAKING_PREDICATE); -+ this.breakDoorGoal = new BreakDoorGoal(this, com.google.common.base.Predicates.in(world.paperConfig().entities.behavior.doorBreakingDifficulty.getOrDefault(type, world.paperConfig().entities.behavior.doorBreakingDifficulty.get(EntityType.ZOMBIE)))); // Paper - Configurable door breaking difficulty - } - - public Zombie(Level world) { -@@ -103,7 +112,7 @@ - - @Override - protected void registerGoals() { -- this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3)); -+ if (this.level().paperConfig().entities.behavior.zombiesTargetTurtleEggs) this.goalSelector.addGoal(4, new Zombie.ZombieAttackTurtleEggGoal(this, 1.0D, 3)); // Paper - Add zombie targets turtle egg config - this.goalSelector.addGoal(8, new LookAtPlayerGoal(this, Player.class, 8.0F)); - this.goalSelector.addGoal(8, new RandomLookAroundGoal(this)); - this.addBehaviourGoals(); -@@ -115,7 +124,7 @@ - this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D)); - this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers(ZombifiedPiglin.class)); - this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, true)); -- this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); -+ if ( this.level().spigotConfig.zombieAggressiveTowardsVillager ) this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, AbstractVillager.class, false)); // Spigot - this.targetSelector.addGoal(3, new NearestAttackableTargetGoal<>(this, IronGolem.class, true)); - this.targetSelector.addGoal(5, new NearestAttackableTargetGoal<>(this, Turtle.class, 10, true, false, Turtle.BABY_ON_LAND_SELECTOR)); - } -@@ -165,11 +174,16 @@ - - @Override - protected int getBaseExperienceReward(ServerLevel world) { -+ final int previousReward = this.xpReward; // Paper - store previous value to reset after calculating XP reward - if (this.isBaby()) { - this.xpReward = (int) ((double) this.xpReward * 2.5D); - } - -- return super.getBaseExperienceReward(world); -+ // Paper start - store previous value to reset after calculating XP reward -+ int reward = super.getBaseExperienceReward(world); -+ this.xpReward = previousReward; -+ return reward; -+ // Paper end - store previous value to reset after calculating XP reward - } - - @Override -@@ -178,9 +192,9 @@ - if (this.level() != null && !this.level().isClientSide) { - AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED); - -- attributemodifiable.removeModifier(Zombie.SPEED_MODIFIER_BABY_ID); -+ attributemodifiable.removeModifier(this.babyModifier.id()); // Paper - Make baby speed configurable - if (baby) { -- attributemodifiable.addTransientModifier(Zombie.SPEED_MODIFIER_BABY); -+ attributemodifiable.addTransientModifier(this.babyModifier); // Paper - Make baby speed configurable - } - } - -@@ -203,7 +217,7 @@ - public void tick() { - if (!this.level().isClientSide && this.isAlive() && !this.isNoAi()) { - if (this.isUnderWaterConverting()) { -- --this.conversionTime; -+ --this.conversionTime; // Paper - remove anti tick skipping measures / wall time - if (this.conversionTime < 0) { - this.doUnderWaterConversion(); - } -@@ -220,6 +234,7 @@ - } - - super.tick(); -+ // this.lastTick = MinecraftServer.currentTick; // CraftBukkit // Paper - remove anti tick skipping measures / wall time - } - - @Override -@@ -253,7 +268,14 @@ - super.aiStep(); - } - -+ // Paper start - Add more Zombie API -+ public void stopDrowning() { -+ this.conversionTime = -1; -+ this.getEntityData().set(Zombie.DATA_DROWNED_CONVERSION_ID, false); -+ } -+ // Paper end - Add more Zombie API - public void startUnderWaterConversion(int ticksUntilWaterConversion) { -+ // this.lastTick = MinecraftServer.currentTick; // CraftBukkit // Paper - remove anti tick skipping measures / wall time - this.conversionTime = ticksUntilWaterConversion; - this.getEntityData().set(Zombie.DATA_DROWNED_CONVERSION_ID, true); - } -@@ -267,32 +289,51 @@ - } - - protected void convertToZombieType(EntityType entityType) { -- this.convertTo(entityType, ConversionParams.single(this, true, true), (entityzombie) -> { -+ Zombie converted = this.convertTo(entityType, ConversionParams.single(this, true, true), (entityzombie) -> { // CraftBukkit - entityzombie.handleAttributes(entityzombie.level().getCurrentDifficultyAt(entityzombie.blockPosition()).getSpecialMultiplier()); -- }); -+ // CraftBukkit start -+ }, EntityTransformEvent.TransformReason.DROWNED, CreatureSpawnEvent.SpawnReason.DROWNED); -+ if (converted == null) { -+ ((org.bukkit.entity.Zombie) this.getBukkitEntity()).setConversionTime(-1); // CraftBukkit - SPIGOT-5208: End conversion to stop event spam -+ } -+ // CraftBukkit end - } - - @VisibleForTesting - public boolean convertVillagerToZombieVillager(ServerLevel world, Villager villager) { -- ZombieVillager entityzombievillager = (ZombieVillager) villager.convertTo(EntityType.ZOMBIE_VILLAGER, ConversionParams.single(villager, true, true), (entityzombievillager1) -> { -- entityzombievillager1.finalizeSpawn(world, world.getCurrentDifficultyAt(entityzombievillager1.blockPosition()), EntitySpawnReason.CONVERSION, new Zombie.ZombieGroupData(false, true)); -- entityzombievillager1.setVillagerData(villager.getVillagerData()); -- entityzombievillager1.setGossips((Tag) villager.getGossips().store(NbtOps.INSTANCE)); -- entityzombievillager1.setTradeOffers(villager.getOffers().copy()); -- entityzombievillager1.setVillagerXp(villager.getVillagerXp()); -- if (!this.isSilent()) { -- world.levelEvent((Player) null, 1026, this.blockPosition(), 0); -+ // CraftBukkit start -+ return Zombie.convertVillagerToZombieVillager(world, villager, this.blockPosition(), this.isSilent(), EntityTransformEvent.TransformReason.INFECTION, CreatureSpawnEvent.SpawnReason.INFECTION) != null; -+ } -+ -+ public static ZombieVillager convertVillagerToZombieVillager(ServerLevel worldserver, Villager entityvillager, net.minecraft.core.BlockPos blockPosition, boolean silent, EntityTransformEvent.TransformReason transformReason, CreatureSpawnEvent.SpawnReason spawnReason) { -+ // CraftBukkit end -+ ZombieVillager entityzombievillager = (ZombieVillager) entityvillager.convertTo(EntityType.ZOMBIE_VILLAGER, ConversionParams.single(entityvillager, true, true), (entityzombievillager1) -> { -+ entityzombievillager1.finalizeSpawn(worldserver, worldserver.getCurrentDifficultyAt(entityzombievillager1.blockPosition()), EntitySpawnReason.CONVERSION, new Zombie.ZombieGroupData(false, true)); -+ entityzombievillager1.setVillagerData(entityvillager.getVillagerData()); -+ entityzombievillager1.setGossips((Tag) entityvillager.getGossips().store(NbtOps.INSTANCE)); -+ entityzombievillager1.setTradeOffers(entityvillager.getOffers().copy()); -+ entityzombievillager1.setVillagerXp(entityvillager.getVillagerXp()); -+ // CraftBukkit start -+ if (!silent) { -+ worldserver.levelEvent((Player) null, 1026, blockPosition, 0); - } - -- }); -+ }, transformReason, spawnReason); - -- return entityzombievillager != null; -+ return entityzombievillager; -+ // CraftBukkit end - } - - public boolean isSunSensitive() { -- return true; -+ return this.shouldBurnInDay; // Paper - Add more Zombie API - } - -+ // Paper start - Add more Zombie API -+ public void setShouldBurnInDay(boolean shouldBurnInDay) { -+ this.shouldBurnInDay = shouldBurnInDay; -+ } -+ // Paper end - Add more Zombie API -+ - @Override - public boolean hurtServer(ServerLevel world, DamageSource source, float amount) { - if (!super.hurtServer(world, source, amount)) { -@@ -323,10 +364,10 @@ - - if (SpawnPlacements.isSpawnPositionOk(entitytypes, world, blockposition) && SpawnPlacements.checkSpawnRules(entitytypes, world, EntitySpawnReason.REINFORCEMENT, blockposition, world.random)) { - entityzombie.setPos((double) i1, (double) j1, (double) k1); -- if (!world.hasNearbyAlivePlayer((double) i1, (double) j1, (double) k1, 7.0D) && world.isUnobstructed(entityzombie) && world.noCollision((Entity) entityzombie) && (entityzombie.canSpawnInLiquids() || !world.containsAnyLiquid(entityzombie.getBoundingBox()))) { -- entityzombie.setTarget(entityliving); -+ if (!world.hasNearbyAlivePlayerThatAffectsSpawning((double) i1, (double) j1, (double) k1, 7.0D) && world.isUnobstructed(entityzombie) && world.noCollision((Entity) entityzombie) && (entityzombie.canSpawnInLiquids() || !world.containsAnyLiquid(entityzombie.getBoundingBox()))) { // Paper - affects spawning api -+ entityzombie.setTarget(entityliving, EntityTargetEvent.TargetReason.REINFORCEMENT_TARGET, true); // CraftBukkit - entityzombie.finalizeSpawn(world, world.getCurrentDifficultyAt(entityzombie.blockPosition()), EntitySpawnReason.REINFORCEMENT, (SpawnGroupData) null); -- world.addFreshEntityWithPassengers(entityzombie); -+ world.addFreshEntityWithPassengers(entityzombie, CreatureSpawnEvent.SpawnReason.REINFORCEMENTS); // CraftBukkit - AttributeInstance attributemodifiable = this.getAttribute(Attributes.SPAWN_REINFORCEMENTS_CHANCE); - AttributeModifier attributemodifier = attributemodifiable.getModifier(Zombie.REINFORCEMENT_CALLER_CHARGE_ID); - double d0 = attributemodifier != null ? attributemodifier.amount() : 0.0D; -@@ -352,7 +393,14 @@ - float f = this.level().getCurrentDifficultyAt(this.blockPosition()).getEffectiveDifficulty(); - - if (this.getMainHandItem().isEmpty() && this.isOnFire() && this.random.nextFloat() < f * 0.3F) { -- target.igniteForSeconds((float) (2 * (int) f)); -+ // CraftBukkit start -+ EntityCombustByEntityEvent event = new EntityCombustByEntityEvent(this.getBukkitEntity(), target.getBukkitEntity(), (float) (2 * (int) f)); // PAIL: fixme -+ this.level().getCraftServer().getPluginManager().callEvent(event); -+ -+ if (!event.isCancelled()) { -+ target.igniteForSeconds(event.getDuration(), false); -+ } -+ // CraftBukkit end - } - } - -@@ -385,7 +433,7 @@ - - @Override - public EntityType getType() { -- return super.getType(); -+ return (EntityType) super.getType(); // CraftBukkit - decompile error - } - - protected boolean canSpawnInLiquids() { -@@ -414,6 +462,7 @@ - nbt.putBoolean("CanBreakDoors", this.canBreakDoors()); - nbt.putInt("InWaterTime", this.isInWater() ? this.inWaterTime : -1); - nbt.putInt("DrownedConversionTime", this.isUnderWaterConverting() ? this.conversionTime : -1); -+ nbt.putBoolean("Paper.ShouldBurnInDay", this.shouldBurnInDay); // Paper - Add more Zombie API - } - - @Override -@@ -425,6 +474,11 @@ - if (nbt.contains("DrownedConversionTime", 99) && nbt.getInt("DrownedConversionTime") > -1) { - this.startUnderWaterConversion(nbt.getInt("DrownedConversionTime")); - } -+ // Paper start - Add more Zombie API -+ if (nbt.contains("Paper.ShouldBurnInDay")) { -+ this.shouldBurnInDay = nbt.getBoolean("Paper.ShouldBurnInDay"); -+ } -+ // Paper end - Add more Zombie API - - } - -@@ -432,10 +486,8 @@ - public boolean killedEntity(ServerLevel world, LivingEntity other) { - boolean flag = super.killedEntity(world, other); - -- if ((world.getDifficulty() == Difficulty.NORMAL || world.getDifficulty() == Difficulty.HARD) && other instanceof Villager entityvillager) { -- if (world.getDifficulty() != Difficulty.HARD && this.random.nextBoolean()) { -- return flag; -- } -+ final double fallbackChance = world.getDifficulty() == Difficulty.HARD ? 100d : world.getDifficulty() == Difficulty.NORMAL ? 50d : 0d; // Paper - Configurable chance of villager zombie infection -+ if (this.random.nextDouble() * 100 < world.paperConfig().entities.behavior.zombieVillagerInfectionChance.or(fallbackChance) && other instanceof Villager entityvillager) { // Paper - Configurable chance of villager zombie infection - - if (this.convertVillagerToZombieVillager(world, entityvillager)) { - flag = false; -@@ -468,7 +520,7 @@ - float f = difficulty.getSpecialMultiplier(); - - if (spawnReason != EntitySpawnReason.CONVERSION) { -- this.setCanPickUpLoot(randomsource.nextFloat() < 0.55F * f); -+ this.setCanPickUpLoot(this.level().paperConfig().entities.behavior.mobsCanAlwaysPickUpLoot.zombies || randomsource.nextFloat() < 0.55F * f); // Paper - Add world settings for mobs picking up loot - } - - if (object == null) { -@@ -496,7 +548,7 @@ - entitychicken1.finalizeSpawn(world, difficulty, EntitySpawnReason.JOCKEY, (SpawnGroupData) null); - entitychicken1.setChickenJockey(true); - this.startRiding(entitychicken1); -- world.addFreshEntity(entitychicken1); -+ world.addFreshEntity(entitychicken1, CreatureSpawnEvent.SpawnReason.MOUNT); // CraftBukkit - } - } - } diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/ZombieVillager.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/ZombieVillager.java.patch deleted file mode 100644 index d025644b62..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/ZombieVillager.java.patch +++ /dev/null @@ -1,149 +0,0 @@ ---- a/net/minecraft/world/entity/monster/ZombieVillager.java -+++ b/net/minecraft/world/entity/monster/ZombieVillager.java -@@ -18,10 +18,6 @@ - import net.minecraft.network.syncher.EntityDataAccessor; - import net.minecraft.network.syncher.EntityDataSerializers; - import net.minecraft.network.syncher.SynchedEntityData; --import net.minecraft.server.level.ServerLevel; --import net.minecraft.server.level.ServerPlayer; --import net.minecraft.sounds.SoundEvent; --import net.minecraft.sounds.SoundEvents; - import net.minecraft.world.DifficultyInstance; - import net.minecraft.world.InteractionHand; - import net.minecraft.world.InteractionResult; -@@ -35,6 +31,7 @@ - import net.minecraft.world.entity.SlotAccess; - import net.minecraft.world.entity.SpawnGroupData; - import net.minecraft.world.entity.ai.village.ReputationEventType; -+import net.minecraft.world.entity.npc.Villager; - import net.minecraft.world.entity.npc.VillagerData; - import net.minecraft.world.entity.npc.VillagerDataHolder; - import net.minecraft.world.entity.npc.VillagerProfession; -@@ -52,6 +49,16 @@ - import net.minecraft.world.level.block.state.BlockState; - import org.slf4j.Logger; - -+// CraftBukkit start -+import net.minecraft.server.MinecraftServer; -+import net.minecraft.server.level.ServerLevel; -+import net.minecraft.server.level.ServerPlayer; -+import net.minecraft.sounds.SoundEvent; -+import net.minecraft.sounds.SoundEvents; -+import org.bukkit.event.entity.CreatureSpawnEvent; -+import org.bukkit.event.entity.EntityTransformEvent; -+// CraftBukkit end -+ - public class ZombieVillager extends Zombie implements VillagerDataHolder { - - private static final Logger LOGGER = LogUtils.getLogger(); -@@ -69,6 +76,7 @@ - @Nullable - private MerchantOffers tradeOffers; - private int villagerXp; -+ private int lastTick = MinecraftServer.currentTick; // CraftBukkit - add field - - public ZombieVillager(EntityType type, Level world) { - super(type, world); -@@ -87,7 +95,7 @@ - @Override - public void addAdditionalSaveData(CompoundTag nbt) { - super.addAdditionalSaveData(nbt); -- DataResult dataresult = VillagerData.CODEC.encodeStart(NbtOps.INSTANCE, this.getVillagerData()); -+ DataResult dataresult = VillagerData.CODEC.encodeStart(NbtOps.INSTANCE, this.getVillagerData()); // CraftBukkit - decompile error - Logger logger = ZombieVillager.LOGGER; - - Objects.requireNonNull(logger); -@@ -122,7 +130,7 @@ - } - - if (nbt.contains("Offers")) { -- DataResult dataresult1 = MerchantOffers.CODEC.parse(this.registryAccess().createSerializationContext(NbtOps.INSTANCE), nbt.get("Offers")); -+ DataResult dataresult1 = MerchantOffers.CODEC.parse(this.registryAccess().createSerializationContext(NbtOps.INSTANCE), nbt.get("Offers")); // CraftBukkit - decompile error - Logger logger1 = ZombieVillager.LOGGER; - - Objects.requireNonNull(logger1); -@@ -149,6 +157,10 @@ - public void tick() { - if (!this.level().isClientSide && this.isAlive() && this.isConverting()) { - int i = this.getConversionProgress(); -+ // CraftBukkit start - Use wall time instead of ticks for villager conversion -+ int elapsedTicks = MinecraftServer.currentTick - this.lastTick; -+ i *= elapsedTicks; -+ // CraftBukkit end - - this.villagerConversionTime -= i; - if (this.villagerConversionTime <= 0) { -@@ -157,6 +169,7 @@ - } - - super.tick(); -+ this.lastTick = MinecraftServer.currentTick; // CraftBukkit - } - - @Override -@@ -194,12 +207,20 @@ - } - - public void startConverting(@Nullable UUID uuid, int delay) { -+ // Paper start - missing entity behaviour api - converting without entity event -+ this.startConverting(uuid, delay, true); -+ } -+ -+ public void startConverting(@Nullable UUID uuid, int delay, boolean broadcastEntityEvent) { -+ // Paper end - missing entity behaviour api - converting without entity event - this.conversionStarter = uuid; - this.villagerConversionTime = delay; - this.getEntityData().set(ZombieVillager.DATA_CONVERTING_ID, true); -- this.removeEffect(MobEffects.WEAKNESS); -- this.addEffect(new MobEffectInstance(MobEffects.DAMAGE_BOOST, delay, Math.min(this.level().getDifficulty().getId() - 1, 0))); -- this.level().broadcastEntityEvent(this, (byte) 16); -+ // CraftBukkit start -+ this.removeEffect(MobEffects.WEAKNESS, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); -+ this.addEffect(new MobEffectInstance(MobEffects.DAMAGE_BOOST, delay, Math.min(this.level().getDifficulty().getId() - 1, 0)), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); -+ // CraftBukkit end -+ if (broadcastEntityEvent) this.level().broadcastEntityEvent(this, (byte) 16); // Paper - missing entity behaviour api - converting without entity event - } - - @Override -@@ -215,10 +236,11 @@ - } - - private void finishConversion(ServerLevel world) { -- this.convertTo(EntityType.VILLAGER, ConversionParams.single(this, false, false), (entityvillager) -> { -+ Villager converted = this.convertTo(EntityType.VILLAGER, ConversionParams.single(this, false, false), (entityvillager) -> { // CraftBukkit - Iterator iterator = this.dropPreservedEquipment(world, (itemstack) -> { - return !EnchantmentHelper.has(itemstack, EnchantmentEffectComponents.PREVENT_ARMOR_CHANGE); - }).iterator(); -+ this.forceDrops = false; // CraftBukkit - - while (iterator.hasNext()) { - EquipmentSlot enumitemslot = (EquipmentSlot) iterator.next(); -@@ -240,7 +262,7 @@ - entityvillager.finalizeSpawn(world, world.getCurrentDifficultyAt(entityvillager.blockPosition()), EntitySpawnReason.CONVERSION, (SpawnGroupData) null); - entityvillager.refreshBrain(world); - if (this.conversionStarter != null) { -- Player entityhuman = world.getPlayerByUUID(this.conversionStarter); -+ Player entityhuman = world.getGlobalPlayerByUUID(this.conversionStarter); // Paper - check global player list where appropriate - - if (entityhuman instanceof ServerPlayer) { - CriteriaTriggers.CURED_ZOMBIE_VILLAGER.trigger((ServerPlayer) entityhuman, this, entityvillager); -@@ -248,12 +270,16 @@ - } - } - -- entityvillager.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0)); -+ entityvillager.addEffect(new MobEffectInstance(MobEffects.CONFUSION, 200, 0), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.CONVERSION); // CraftBukkit - if (!this.isSilent()) { - world.levelEvent((Player) null, 1027, this.blockPosition(), 0); - } -- -- }); -+ // CraftBukkit start -+ }, EntityTransformEvent.TransformReason.CURED, CreatureSpawnEvent.SpawnReason.CURED); -+ if (converted == null) { -+ ((org.bukkit.entity.ZombieVillager) this.getBukkitEntity()).setConversionTime(-1); // SPIGOT-5208: End conversion to stop event spam -+ } -+ // CraftBukkit end - } - - @VisibleForTesting diff --git a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch b/paper-server/patches/unapplied/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch deleted file mode 100644 index 0b3d7e043c..0000000000 --- a/paper-server/patches/unapplied/net/minecraft/world/entity/monster/ZombifiedPiglin.java.patch +++ /dev/null @@ -1,67 +0,0 @@ ---- a/net/minecraft/world/entity/monster/ZombifiedPiglin.java -+++ b/net/minecraft/world/entity/monster/ZombifiedPiglin.java -@@ -56,6 +56,7 @@ - private static final int ALERT_RANGE_Y = 10; - private static final UniformInt ALERT_INTERVAL = TimeUtil.rangeOfSeconds(4, 6); - private int ticksUntilNextAlert; -+ private HurtByTargetGoal pathfinderGoalHurtByTarget; // Paper - fix PigZombieAngerEvent cancellation - - public ZombifiedPiglin(EntityType type, Level world) { - super(type, world); -@@ -71,7 +72,7 @@ - protected void addBehaviourGoals() { - this.goalSelector.addGoal(2, new ZombieAttackGoal(this, 1.0D, false)); - this.goalSelector.addGoal(7, new WaterAvoidingRandomStrollGoal(this, 1.0D)); -- this.targetSelector.addGoal(1, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers()); -+ this.targetSelector.addGoal(1, pathfinderGoalHurtByTarget = (new HurtByTargetGoal(this, new Class[0])).setAlertOthers()); // Paper - fix PigZombieAngerEvent cancellation - this.targetSelector.addGoal(2, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt)); - this.targetSelector.addGoal(3, new ResetUniversalAngerTargetGoal<>(this, true)); - } -@@ -149,7 +150,7 @@ - }).filter((entitypigzombie) -> { - return !entitypigzombie.isAlliedTo((Entity) this.getTarget()); - }).forEach((entitypigzombie) -> { -- entitypigzombie.setTarget(this.getTarget()); -+ entitypigzombie.setTarget(this.getTarget(), org.bukkit.event.entity.EntityTargetEvent.TargetReason.TARGET_ATTACKED_NEARBY_ENTITY, true); // CraftBukkit - }); - } - -@@ -158,22 +159,32 @@ - } - - @Override -- public void setTarget(@Nullable LivingEntity target) { -- if (this.getTarget() == null && target != null) { -+ public boolean setTarget(@Nullable LivingEntity entityliving, org.bukkit.event.entity.EntityTargetEvent.TargetReason reason, boolean fireEvent) { // CraftBukkit - signature -+ if (this.getTarget() == null && entityliving != null) { - this.playFirstAngerSoundIn = ZombifiedPiglin.FIRST_ANGER_SOUND_DELAY.sample(this.random); - this.ticksUntilNextAlert = ZombifiedPiglin.ALERT_INTERVAL.sample(this.random); - } - -- if (target instanceof Player) { -- this.setLastHurtByPlayer((Player) target); -+ if (entityliving instanceof Player) { -+ this.setLastHurtByPlayer((Player) entityliving); - } - -- super.setTarget(target); -+ return super.setTarget(entityliving, reason, fireEvent); // CraftBukkit - } - - @Override - public void startPersistentAngerTimer() { -- this.setRemainingPersistentAngerTime(ZombifiedPiglin.PERSISTENT_ANGER_TIME.sample(this.random)); -+ // CraftBukkit start -+ Entity entity = ((ServerLevel) this.level()).getEntity(this.getPersistentAngerTarget()); -+ org.bukkit.event.entity.PigZombieAngerEvent event = new org.bukkit.event.entity.PigZombieAngerEvent((org.bukkit.entity.PigZombie) this.getBukkitEntity(), (entity == null) ? null : entity.getBukkitEntity(), ZombifiedPiglin.PERSISTENT_ANGER_TIME.sample(this.random)); -+ this.level().getCraftServer().getPluginManager().callEvent(event); -+ if (event.isCancelled()) { -+ this.setPersistentAngerTarget(null); -+ pathfinderGoalHurtByTarget.stop(); // Paper - fix PigZombieAngerEvent cancellation -+ return; -+ } -+ this.setRemainingPersistentAngerTime(event.getNewAnger()); -+ // CraftBukkit end - } - - public static boolean checkZombifiedPiglinSpawnRules(EntityType type, LevelAccessor world, EntitySpawnReason spawnReason, BlockPos pos, RandomSource random) {