aboutsummaryrefslogtreecommitdiffhomepage
path: root/patch-remap/mache-spigotflower/net/minecraft/world/entity/LivingEntity.java.patch
diff options
context:
space:
mode:
Diffstat (limited to 'patch-remap/mache-spigotflower/net/minecraft/world/entity/LivingEntity.java.patch')
-rw-r--r--patch-remap/mache-spigotflower/net/minecraft/world/entity/LivingEntity.java.patch4042
1 files changed, 4042 insertions, 0 deletions
diff --git a/patch-remap/mache-spigotflower/net/minecraft/world/entity/LivingEntity.java.patch b/patch-remap/mache-spigotflower/net/minecraft/world/entity/LivingEntity.java.patch
new file mode 100644
index 0000000000..aed1d14b87
--- /dev/null
+++ b/patch-remap/mache-spigotflower/net/minecraft/world/entity/LivingEntity.java.patch
@@ -0,0 +1,4042 @@
+--- a/net/minecraft/world/entity/LivingEntity.java
++++ b/net/minecraft/world/entity/LivingEntity.java
+@@ -29,6 +29,8 @@
+ import net.minecraft.core.particles.ItemParticleOption;
+ import net.minecraft.core.particles.ParticleTypes;
+ import net.minecraft.nbt.CompoundTag;
++import net.minecraft.nbt.FloatTag;
++import net.minecraft.nbt.IntTag;
+ import net.minecraft.nbt.ListTag;
+ import net.minecraft.nbt.NbtOps;
+ import net.minecraft.nbt.Tag;
+@@ -59,7 +61,7 @@
+ import net.minecraft.util.Mth;
+ import net.minecraft.util.RandomSource;
+ import net.minecraft.world.Difficulty;
+-import net.minecraft.world.InteractionHand;
++import net.minecraft.world.EnumHand;
+ import net.minecraft.world.damagesource.CombatRules;
+ import net.minecraft.world.damagesource.CombatTracker;
+ import net.minecraft.world.damagesource.DamageSource;
+@@ -76,20 +78,19 @@
+ import net.minecraft.world.entity.ai.attributes.Attributes;
+ import net.minecraft.world.entity.ai.attributes.DefaultAttributes;
+ import net.minecraft.world.entity.ai.targeting.TargetingConditions;
+-import net.minecraft.world.entity.animal.FlyingAnimal;
++import net.minecraft.world.entity.animal.EntityBird;
+ import net.minecraft.world.entity.animal.Wolf;
+ import net.minecraft.world.entity.boss.wither.WitherBoss;
+ import net.minecraft.world.entity.item.ItemEntity;
+-import net.minecraft.world.entity.player.Player;
+ import net.minecraft.world.entity.projectile.AbstractArrow;
+ import net.minecraft.world.food.FoodProperties;
+ import net.minecraft.world.item.AxeItem;
+ import net.minecraft.world.item.ElytraItem;
++import net.minecraft.world.item.EnumAnimation;
+ import net.minecraft.world.item.Equipable;
+ import net.minecraft.world.item.Item;
+ import net.minecraft.world.item.ItemStack;
+ import net.minecraft.world.item.Items;
+-import net.minecraft.world.item.UseAnim;
+ import net.minecraft.world.item.alchemy.PotionUtils;
+ import net.minecraft.world.item.enchantment.EnchantmentHelper;
+ import net.minecraft.world.item.enchantment.Enchantments;
+@@ -104,7 +105,7 @@
+ import net.minecraft.world.level.block.PowderSnowBlock;
+ import net.minecraft.world.level.block.SoundType;
+ import net.minecraft.world.level.block.TrapDoorBlock;
+-import net.minecraft.world.level.block.state.BlockState;
++import net.minecraft.world.level.block.state.IBlockData;
+ import net.minecraft.world.level.entity.EntityTypeTest;
+ import net.minecraft.world.level.gameevent.GameEvent;
+ import net.minecraft.world.level.material.Fluid;
+@@ -119,6 +120,26 @@
+ import net.minecraft.world.scores.PlayerTeam;
+ import org.slf4j.Logger;
+
++// CraftBukkit start
++import java.util.ArrayList;
++import java.util.HashSet;
++import java.util.Set;
++import com.google.common.base.Function;
++import org.bukkit.Location;
++import org.bukkit.craftbukkit.attribute.CraftAttributeMap;
++import org.bukkit.craftbukkit.event.CraftEventFactory;
++import org.bukkit.craftbukkit.inventory.CraftItemStack;
++import org.bukkit.entity.Player;
++import org.bukkit.event.entity.ArrowBodyCountChangeEvent;
++import org.bukkit.event.entity.EntityDamageEvent;
++import org.bukkit.event.entity.EntityDamageEvent.DamageModifier;
++import org.bukkit.event.entity.EntityPotionEffectEvent;
++import org.bukkit.event.entity.EntityRegainHealthEvent;
++import org.bukkit.event.entity.EntityResurrectEvent;
++import org.bukkit.event.entity.EntityTeleportEvent;
++import org.bukkit.event.player.PlayerItemConsumeEvent;
++// CraftBukkit end
++
+ public abstract class LivingEntity extends Entity implements Attackable {
+
+ private static final Logger LOGGER = LogUtils.getLogger();
+@@ -146,23 +167,23 @@
+ protected static final int LIVING_ENTITY_FLAG_OFF_HAND = 2;
+ protected static final int LIVING_ENTITY_FLAG_SPIN_ATTACK = 4;
+ protected static final EntityDataAccessor<Byte> DATA_LIVING_ENTITY_FLAGS = SynchedEntityData.defineId(LivingEntity.class, EntityDataSerializers.BYTE);
+- private static final EntityDataAccessor<Float> DATA_HEALTH_ID = SynchedEntityData.defineId(LivingEntity.class, EntityDataSerializers.FLOAT);
++ public static final EntityDataAccessor<Float> DATA_HEALTH_ID = SynchedEntityData.defineId(LivingEntity.class, EntityDataSerializers.FLOAT);
+ private static final EntityDataAccessor<Integer> DATA_EFFECT_COLOR_ID = SynchedEntityData.defineId(LivingEntity.class, EntityDataSerializers.INT);
+ private static final EntityDataAccessor<Boolean> DATA_EFFECT_AMBIENCE_ID = SynchedEntityData.defineId(LivingEntity.class, EntityDataSerializers.BOOLEAN);
+- private static final EntityDataAccessor<Integer> DATA_ARROW_COUNT_ID = SynchedEntityData.defineId(LivingEntity.class, EntityDataSerializers.INT);
++ public static final EntityDataAccessor<Integer> DATA_ARROW_COUNT_ID = SynchedEntityData.defineId(LivingEntity.class, EntityDataSerializers.INT);
+ private static final EntityDataAccessor<Integer> DATA_STINGER_COUNT_ID = SynchedEntityData.defineId(LivingEntity.class, EntityDataSerializers.INT);
+ private static final EntityDataAccessor<Optional<BlockPos>> SLEEPING_POS_ID = SynchedEntityData.defineId(LivingEntity.class, EntityDataSerializers.OPTIONAL_BLOCK_POS);
+ protected static final float DEFAULT_EYE_HEIGHT = 1.74F;
+ protected static final EntityDimensions SLEEPING_DIMENSIONS = EntityDimensions.fixed(0.2F, 0.2F);
+ public static final float EXTRA_RENDER_CULLING_SIZE_WITH_BIG_HAT = 0.5F;
+ private final AttributeMap attributes;
+- private final CombatTracker combatTracker = new CombatTracker(this);
+- private final Map<MobEffect, MobEffectInstance> activeEffects = Maps.newHashMap();
++ public CombatTracker combatTracker = new CombatTracker(this);
++ public final Map<MobEffect, MobEffectInstance> activeEffects = Maps.newHashMap();
+ private final NonNullList<ItemStack> lastHandItemStacks;
+ private final NonNullList<ItemStack> lastArmorItemStacks;
+ public boolean swinging;
+ private boolean discardFriction;
+- public InteractionHand swingingArm;
++ public EnumHand swingingArm;
+ public int swingTime;
+ public int removeArrowTime;
+ public int removeStingerTime;
+@@ -173,7 +194,7 @@
+ public float attackAnim;
+ protected int attackStrengthTicker;
+ public final WalkAnimationState walkAnimation;
+- public final int invulnerableDuration;
++ public int invulnerableDuration;
+ public final float timeOffs;
+ public final float rotA;
+ public float yBodyRot;
+@@ -181,7 +202,7 @@
+ public float yHeadRot;
+ public float yHeadRotO;
+ @Nullable
+- protected Player lastHurtByPlayer;
++ public net.minecraft.world.entity.player.Player lastHurtByPlayer;
+ protected int lastHurtByPlayerTime;
+ protected boolean dead;
+ protected int noActionTime;
+@@ -191,7 +212,7 @@
+ protected float animStepO;
+ protected float rotOffs;
+ protected int deathScore;
+- protected float lastHurt;
++ public float lastHurt;
+ protected boolean jumping;
+ public float xxa;
+ public float yya;
+@@ -204,10 +225,10 @@
+ protected double lerpXRot;
+ protected double lerpYHeadRot;
+ protected int lerpHeadSteps;
+- private boolean effectsDirty;
++ public boolean effectsDirty;
+ @Nullable
+- private LivingEntity lastHurtByMob;
+- private int lastHurtByMobTimestamp;
++ public LivingEntity lastHurtByMob;
++ public int lastHurtByMobTimestamp;
+ private LivingEntity lastHurtMob;
+ private int lastHurtMobTimestamp;
+ private float speed;
+@@ -226,9 +247,23 @@
+ private float swimAmountO;
+ protected Brain<?> brain;
+ private boolean skipDropExperience;
++ // CraftBukkit start
++ public int expToDrop;
++ public boolean forceDrops;
++ public ArrayList<org.bukkit.inventory.ItemStack> drops = new ArrayList<org.bukkit.inventory.ItemStack>();
++ public final org.bukkit.craftbukkit.attribute.CraftAttributeMap craftAttributes;
++ public boolean collides = true;
++ public Set<UUID> collidableExemptions = new HashSet<>();
++ public boolean bukkitPickUpLoot;
+
+- protected LivingEntity(EntityType<? extends LivingEntity> entitytype, Level level) {
+- super(entitytype, level);
++ @Override
++ public float getBukkitYaw() {
++ return getYHeadRot();
++ }
++ // CraftBukkit end
++
++ protected LivingEntity(EntityType<? extends LivingEntity> entityType, Level level) {
++ super(entityType, level);
+ this.lastHandItemStacks = NonNullList.withSize(2, ItemStack.EMPTY);
+ this.lastArmorItemStacks = NonNullList.withSize(4, ItemStack.EMPTY);
+ this.discardFriction = false;
+@@ -237,8 +272,10 @@
+ this.effectsDirty = true;
+ this.useItem = ItemStack.EMPTY;
+ this.lastClimbablePos = Optional.empty();
+- this.attributes = new AttributeMap(DefaultAttributes.getSupplier(entitytype));
+- this.setHealth(this.getMaxHealth());
++ this.attributes = new AttributeMap(DefaultAttributes.getSupplier(entityType));
++ this.craftAttributes = new CraftAttributeMap(attributes); // CraftBukkit
++ // CraftBukkit - setHealth(getMaxHealth()) inlined and simplified to skip the instanceof check for EntityPlayer, as getBukkitEntity() is not initialized in constructor
++ this.entityData.set(LivingEntity.DATA_HEALTH_ID, (float) this.getAttribute(Attributes.MAX_HEALTH).getValue());
+ this.blocksBuilding = true;
+ this.rotA = (float) ((Math.random() + 1.0D) * 0.009999999776482582D);
+ this.reapplyPosition();
+@@ -246,9 +283,9 @@
+ this.setYRot((float) (Math.random() * 6.2831854820251465D));
+ this.yHeadRot = this.getYRot();
+ this.setMaxUpStep(0.6F);
+- NbtOps nbtops = NbtOps.INSTANCE;
++ NbtOps dynamicopsnbt = NbtOps.INSTANCE;
+
+- this.brain = this.makeBrain(new Dynamic(nbtops, (Tag) nbtops.createMap((Map) ImmutableMap.of(nbtops.createString("memories"), (Tag) nbtops.emptyMap()))));
++ this.brain = this.makeBrain(new Dynamic(dynamicopsnbt, (Tag) dynamicopsnbt.createMap((Map) ImmutableMap.of(dynamicopsnbt.createString("memories"), (Tag) dynamicopsnbt.emptyMap()))));
+ }
+
+ public Brain<?> getBrain() {
+@@ -264,17 +301,15 @@
+ }
+
+ @Override
+- @Override
+ public void kill() {
+ this.hurt(this.damageSources().genericKill(), Float.MAX_VALUE);
+ }
+
+- public boolean canAttackType(EntityType<?> entitytype) {
++ public boolean canAttackType(EntityType<?> entityType) {
+ return true;
+ }
+
+ @Override
+- @Override
+ protected void defineSynchedData() {
+ this.entityData.define(LivingEntity.DATA_LIVING_ENTITY_FLAGS, (byte) 0);
+ this.entityData.define(LivingEntity.DATA_EFFECT_COLOR_ID, 0);
+@@ -290,8 +325,7 @@
+ }
+
+ @Override
+- @Override
+- protected void checkFallDamage(double d0, boolean flag, BlockState blockstate, BlockPos blockpos) {
++ protected void checkFallDamage(double y, boolean flag, IBlockData onGround, BlockPos state) {
+ if (!this.isInWater()) {
+ this.updateInWaterStateAndDoWaterCurrentPushing();
+ }
+@@ -301,29 +335,35 @@
+ this.tryAddSoulSpeed();
+ }
+
+- if (!this.level().isClientSide && this.fallDistance > 3.0F && flag && !blockstate.isAir()) {
++ if (!this.level().isClientSide && this.fallDistance > 3.0F && flag && !onGround.isAir()) {
+ double d1 = this.getX();
+ double d2 = this.getY();
+ double d3 = this.getZ();
+- BlockPos blockpos1 = this.blockPosition();
++ BlockPos blockposition1 = this.blockPosition();
+
+- if (blockpos.getX() != blockpos1.getX() || blockpos.getZ() != blockpos1.getZ()) {
+- double d4 = d1 - (double) blockpos.getX() - 0.5D;
+- double d5 = d3 - (double) blockpos.getZ() - 0.5D;
++ if (state.getX() != blockposition1.getX() || state.getZ() != blockposition1.getZ()) {
++ double d4 = d1 - (double) state.getX() - 0.5D;
++ double d5 = d3 - (double) state.getZ() - 0.5D;
+ double d6 = Math.max(Math.abs(d4), Math.abs(d5));
+
+- d1 = (double) blockpos.getX() + 0.5D + d4 / d6 * 0.5D;
+- d3 = (double) blockpos.getZ() + 0.5D + d5 / d6 * 0.5D;
++ d1 = (double) state.getX() + 0.5D + d4 / d6 * 0.5D;
++ d3 = (double) state.getZ() + 0.5D + d5 / d6 * 0.5D;
+ }
+
+ float f = (float) Mth.ceil(this.fallDistance - 3.0F);
+ double d7 = Math.min((double) (0.2F + f / 15.0F), 2.5D);
+ int i = (int) (150.0D * d7);
+
+- ((ServerLevel) this.level()).sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, blockstate), d1, d2, d3, i, 0.0D, 0.0D, 0.0D, 0.15000000596046448D);
++ // CraftBukkit start - visiblity api
++ if (this instanceof ServerPlayer) {
++ ((ServerLevel) this.level()).sendParticles((ServerPlayer) this, new BlockParticleOption(ParticleTypes.BLOCK, onGround), this.getX(), this.getY(), this.getZ(), i, 0.0D, 0.0D, 0.0D, 0.15000000596046448D, false);
++ } else {
++ ((ServerLevel) this.level()).sendParticles(new BlockParticleOption(ParticleTypes.BLOCK, onGround), d1, d2, d3, i, 0.0D, 0.0D, 0.0D, 0.15000000596046448D);
++ }
++ // CraftBukkit end
+ }
+
+- super.checkFallDamage(d0, flag, blockstate, blockpos);
++ super.checkFallDamage(y, flag, onGround, state);
+ if (flag) {
+ this.lastClimbablePos = Optional.empty();
+ }
+@@ -334,12 +374,11 @@
+ return this.getType().is(EntityTypeTags.CAN_BREATHE_UNDER_WATER);
+ }
+
+- public float getSwimAmount(float f) {
+- return Mth.lerp(f, this.swimAmountO, this.swimAmount);
++ public float getSwimAmount(float partialTicks) {
++ return Mth.lerp(partialTicks, this.swimAmountO, this.swimAmount);
+ }
+
+ @Override
+- @Override
+ public void baseTick() {
+ this.oAttackAnim = this.attackAnim;
+ if (this.firstTick) {
+@@ -357,7 +396,7 @@
+ }
+
+ if (this.isAlive()) {
+- boolean flag = this instanceof Player;
++ boolean flag = this instanceof net.minecraft.world.entity.player.Player;
+
+ if (!this.level().isClientSide) {
+ if (this.isInWall()) {
+@@ -376,20 +415,20 @@
+ }
+
+ if (this.isEyeInFluid(FluidTags.WATER) && !this.level().getBlockState(BlockPos.containing(this.getX(), this.getEyeY(), this.getZ())).is(Blocks.BUBBLE_COLUMN)) {
+- boolean flag1 = !this.canBreatheUnderwater() && !MobEffectUtil.hasWaterBreathing(this) && (!flag || !((Player) this).getAbilities().invulnerable);
++ boolean flag1 = !this.canBreatheUnderwater() && !MobEffectUtil.hasWaterBreathing(this) && (!flag || !((net.minecraft.world.entity.player.Player) this).getAbilities().invulnerable);
+
+ if (flag1) {
+ this.setAirSupply(this.decreaseAirSupply(this.getAirSupply()));
+ if (this.getAirSupply() == -20) {
+ this.setAirSupply(0);
+- Vec3 vec3 = this.getDeltaMovement();
++ Vec3 vec3d = this.getDeltaMovement();
+
+ for (int i = 0; i < 8; ++i) {
+ double d2 = this.random.nextDouble() - this.random.nextDouble();
+ double d3 = this.random.nextDouble() - this.random.nextDouble();
+ double d4 = this.random.nextDouble() - this.random.nextDouble();
+
+- this.level().addParticle(ParticleTypes.BUBBLE, this.getX() + d2, this.getY() + d3, this.getZ() + d4, vec3.x, vec3.y, vec3.z);
++ this.level().addParticle(ParticleTypes.BUBBLE, this.getX() + d2, this.getY() + d3, this.getZ() + d4, vec3d.x, vec3d.y, vec3d.z);
+ }
+
+ this.hurt(this.damageSources().drown(), 2.0F);
+@@ -404,11 +443,11 @@
+ }
+
+ if (!this.level().isClientSide) {
+- BlockPos blockpos = this.blockPosition();
++ BlockPos blockposition = this.blockPosition();
+
+- if (!Objects.equal(this.lastPos, blockpos)) {
+- this.lastPos = blockpos;
+- this.onChangedBlock(blockpos);
++ if (!Objects.equal(this.lastPos, blockposition)) {
++ this.lastPos = blockposition;
++ this.onChangedBlock(blockposition);
+ }
+ }
+ }
+@@ -461,9 +500,9 @@
+ }
+
+ protected void spawnSoulSpeedParticle() {
+- Vec3 vec3 = this.getDeltaMovement();
++ Vec3 vec3d = this.getDeltaMovement();
+
+- this.level().addParticle(ParticleTypes.SOUL, this.getX() + (this.random.nextDouble() - 0.5D) * (double) this.getBbWidth(), this.getY() + 0.1D, this.getZ() + (this.random.nextDouble() - 0.5D) * (double) this.getBbWidth(), vec3.x * -0.2D, 0.1D, vec3.z * -0.2D);
++ this.level().addParticle(ParticleTypes.SOUL, this.getX() + (this.random.nextDouble() - 0.5D) * (double) this.getBbWidth(), this.getY() + 0.1D, this.getZ() + (this.random.nextDouble() - 0.5D) * (double) this.getBbWidth(), vec3d.x * -0.2D, 0.1D, vec3d.z * -0.2D);
+ float f = this.random.nextFloat() * 0.4F + this.random.nextFloat() > 0.9F ? 0.6F : 0.0F;
+
+ this.playSound(SoundEvents.SOUL_ESCAPE, f, 0.6F + this.random.nextFloat() * 0.4F);
+@@ -474,21 +513,20 @@
+ }
+
+ @Override
+- @Override
+ protected float getBlockSpeedFactor() {
+ return this.onSoulSpeedBlock() && EnchantmentHelper.getEnchantmentLevel(Enchantments.SOUL_SPEED, this) > 0 ? 1.0F : super.getBlockSpeedFactor();
+ }
+
+- protected boolean shouldRemoveSoulSpeed(BlockState blockstate) {
+- return !blockstate.isAir() || this.isFallFlying();
++ protected boolean shouldRemoveSoulSpeed(IBlockData state) {
++ return !state.isAir() || this.isFallFlying();
+ }
+
+ protected void removeSoulSpeed() {
+- AttributeInstance attributeinstance = this.getAttribute(Attributes.MOVEMENT_SPEED);
++ AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
+
+- if (attributeinstance != null) {
+- if (attributeinstance.getModifier(LivingEntity.SPEED_MODIFIER_SOUL_SPEED_UUID) != null) {
+- attributeinstance.removeModifier(LivingEntity.SPEED_MODIFIER_SOUL_SPEED_UUID);
++ if (attributemodifiable != null) {
++ if (attributemodifiable.getModifier(LivingEntity.SPEED_MODIFIER_SOUL_SPEED_UUID) != null) {
++ attributemodifiable.removeModifier(LivingEntity.SPEED_MODIFIER_SOUL_SPEED_UUID);
+ }
+
+ }
+@@ -499,18 +537,18 @@
+ int i = EnchantmentHelper.getEnchantmentLevel(Enchantments.SOUL_SPEED, this);
+
+ if (i > 0 && this.onSoulSpeedBlock()) {
+- AttributeInstance attributeinstance = this.getAttribute(Attributes.MOVEMENT_SPEED);
++ AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
+
+- if (attributeinstance == null) {
++ if (attributemodifiable == null) {
+ return;
+ }
+
+- attributeinstance.addTransientModifier(new AttributeModifier(LivingEntity.SPEED_MODIFIER_SOUL_SPEED_UUID, "Soul speed boost", (double) (0.03F * (1.0F + (float) i * 0.35F)), AttributeModifier.Operation.ADDITION));
++ attributemodifiable.addTransientModifier(new AttributeModifier(LivingEntity.SPEED_MODIFIER_SOUL_SPEED_UUID, "Soul speed boost", (double) (0.03F * (1.0F + (float) i * 0.35F)), AttributeModifier.Operation.ADDITION));
+ if (this.getRandom().nextFloat() < 0.04F) {
+ ItemStack itemstack = this.getItemBySlot(EquipmentSlot.FEET);
+
+- itemstack.hurtAndBreak(1, this, (livingentity) -> {
+- livingentity.broadcastBreakEvent(EquipmentSlot.FEET);
++ itemstack.hurtAndBreak(1, this, (entityliving) -> {
++ entityliving.broadcastBreakEvent(EquipmentSlot.FEET);
+ });
+ }
+ }
+@@ -519,11 +557,11 @@
+ }
+
+ protected void removeFrost() {
+- AttributeInstance attributeinstance = this.getAttribute(Attributes.MOVEMENT_SPEED);
++ AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
+
+- if (attributeinstance != null) {
+- if (attributeinstance.getModifier(LivingEntity.SPEED_MODIFIER_POWDER_SNOW_UUID) != null) {
+- attributeinstance.removeModifier(LivingEntity.SPEED_MODIFIER_POWDER_SNOW_UUID);
++ if (attributemodifiable != null) {
++ if (attributemodifiable.getModifier(LivingEntity.SPEED_MODIFIER_POWDER_SNOW_UUID) != null) {
++ attributemodifiable.removeModifier(LivingEntity.SPEED_MODIFIER_POWDER_SNOW_UUID);
+ }
+
+ }
+@@ -534,25 +572,25 @@
+ int i = this.getTicksFrozen();
+
+ if (i > 0) {
+- AttributeInstance attributeinstance = this.getAttribute(Attributes.MOVEMENT_SPEED);
++ AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
+
+- if (attributeinstance == null) {
++ if (attributemodifiable == null) {
+ return;
+ }
+
+ float f = -0.05F * this.getPercentFrozen();
+
+- attributeinstance.addTransientModifier(new AttributeModifier(LivingEntity.SPEED_MODIFIER_POWDER_SNOW_UUID, "Powder snow slow", (double) f, AttributeModifier.Operation.ADDITION));
++ attributemodifiable.addTransientModifier(new AttributeModifier(LivingEntity.SPEED_MODIFIER_POWDER_SNOW_UUID, "Powder snow slow", (double) f, AttributeModifier.Operation.ADDITION));
+ }
+ }
+
+ }
+
+- protected void onChangedBlock(BlockPos blockpos) {
++ protected void onChangedBlock(BlockPos pos) {
+ int i = EnchantmentHelper.getEnchantmentLevel(Enchantments.FROST_WALKER, this);
+
+ if (i > 0) {
+- FrostWalkerEnchantment.onEntityMoved(this, this.level(), blockpos, i);
++ FrostWalkerEnchantment.onEntityMoved(this, this.level(), pos, i);
+ }
+
+ if (this.shouldRemoveSoulSpeed(this.getBlockStateOnLegacy())) {
+@@ -591,14 +629,14 @@
+ return !this.isBaby();
+ }
+
+- protected int decreaseAirSupply(int i) {
++ protected int decreaseAirSupply(int currentAir) {
+ int j = EnchantmentHelper.getRespiration(this);
+
+- return j > 0 && this.random.nextInt(j + 1) > 0 ? i : i - 1;
++ return j > 0 && this.random.nextInt(j + 1) > 0 ? currentAir : currentAir - 1;
+ }
+
+- protected int increaseAirSupply(int i) {
+- return Math.min(i + 4, this.getMaxAirSupply());
++ protected int increaseAirSupply(int currentAir) {
++ return Math.min(currentAir + 4, this.getMaxAirSupply());
+ }
+
+ public int getExperienceReward() {
+@@ -619,7 +657,6 @@
+ }
+
+ @Override
+- @Override
+ public LivingEntity getLastAttacker() {
+ return this.getLastHurtByMob();
+ }
+@@ -628,13 +665,13 @@
+ return this.lastHurtByMobTimestamp;
+ }
+
+- public void setLastHurtByPlayer(@Nullable Player player) {
++ public void setLastHurtByPlayer(@Nullable net.minecraft.world.entity.player.Player player) {
+ this.lastHurtByPlayer = player;
+ this.lastHurtByPlayerTime = this.tickCount;
+ }
+
+- public void setLastHurtByMob(@Nullable LivingEntity livingentity) {
+- this.lastHurtByMob = livingentity;
++ public void setLastHurtByMob(@Nullable LivingEntity livingEntity) {
++ this.lastHurtByMob = livingEntity;
+ this.lastHurtByMobTimestamp = this.tickCount;
+ }
+
+@@ -661,34 +698,40 @@
+ return this.noActionTime;
+ }
+
+- public void setNoActionTime(int i) {
+- this.noActionTime = i;
++ public void setNoActionTime(int idleTime) {
++ this.noActionTime = idleTime;
+ }
+
+ public boolean shouldDiscardFriction() {
+ return this.discardFriction;
+ }
+
+- public void setDiscardFriction(boolean flag) {
+- this.discardFriction = flag;
++ public void setDiscardFriction(boolean discardFriction) {
++ this.discardFriction = discardFriction;
+ }
+
+- protected boolean doesEmitEquipEvent(EquipmentSlot equipmentslot) {
++ protected boolean doesEmitEquipEvent(EquipmentSlot slot) {
+ return true;
+ }
+
+- public void onEquipItem(EquipmentSlot equipmentslot, ItemStack itemstack, ItemStack itemstack1) {
++ public void onEquipItem(EquipmentSlot slot, ItemStack oldItem, ItemStack newItem) {
++ // CraftBukkit start
++ onEquipItem(slot, oldItem, newItem, false);
++ }
++
++ public void onEquipItem(EquipmentSlot enumitemslot, ItemStack itemstack, ItemStack itemstack1, boolean silent) {
++ // CraftBukkit end
+ boolean flag = itemstack1.isEmpty() && itemstack.isEmpty();
+
+ if (!flag && !ItemStack.isSameItemSameTags(itemstack, itemstack1) && !this.firstTick) {
+ Equipable equipable = Equipable.get(itemstack1);
+
+ if (!this.level().isClientSide() && !this.isSpectator()) {
+- if (!this.isSilent() && equipable != null && equipable.getEquipmentSlot() == equipmentslot) {
+- this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), equipable.getEquipSound(), this.getSoundSource(), 1.0F, 1.0F);
++ if (!this.isSilent() && equipable != null && equipable.getEquipmentSlot() == enumitemslot && !silent) { // CraftBukkit
++ this.level().playSound((net.minecraft.world.entity.player.Player) null, this.getX(), this.getY(), this.getZ(), equipable.getEquipSound(), this.getSoundSource(), 1.0F, 1.0F);
+ }
+
+- if (this.doesEmitEquipEvent(equipmentslot)) {
++ if (this.doesEmitEquipEvent(enumitemslot)) {
+ this.gameEvent(equipable != null ? GameEvent.EQUIP : GameEvent.UNEQUIP);
+ }
+ }
+@@ -697,129 +740,177 @@
+ }
+
+ @Override
+- @Override
+- public void remove(Entity.RemovalReason entity_removalreason) {
+- super.remove(entity_removalreason);
++ public void remove(Entity.RemovalReason reason) {
++ super.remove(reason);
+ this.brain.clearMemories();
+ }
+
+ @Override
+- @Override
+- public void addAdditionalSaveData(CompoundTag compoundtag) {
+- compoundtag.putFloat("Health", this.getHealth());
+- compoundtag.putShort("HurtTime", (short) this.hurtTime);
+- compoundtag.putInt("HurtByTimestamp", this.lastHurtByMobTimestamp);
+- compoundtag.putShort("DeathTime", (short) this.deathTime);
+- compoundtag.putFloat("AbsorptionAmount", this.getAbsorptionAmount());
+- compoundtag.put("Attributes", this.getAttributes().save());
++ public void addAdditionalSaveData(CompoundTag compound) {
++ compound.putFloat("Health", this.getHealth());
++ compound.putShort("HurtTime", (short) this.hurtTime);
++ compound.putInt("HurtByTimestamp", this.lastHurtByMobTimestamp);
++ compound.putShort("DeathTime", (short) this.deathTime);
++ compound.putFloat("AbsorptionAmount", this.getAbsorptionAmount());
++ compound.put("Attributes", this.getAttributes().save());
+ if (!this.activeEffects.isEmpty()) {
+- ListTag listtag = new ListTag();
++ ListTag nbttaglist = new ListTag();
+ Iterator iterator = this.activeEffects.values().iterator();
+
+ while (iterator.hasNext()) {
+- MobEffectInstance mobeffectinstance = (MobEffectInstance) iterator.next();
++ MobEffectInstance mobeffect = (MobEffectInstance) iterator.next();
+
+- listtag.add(mobeffectinstance.save(new CompoundTag()));
++ nbttaglist.add(mobeffect.save(new CompoundTag()));
+ }
+
+- compoundtag.put("active_effects", listtag);
++ compound.put("active_effects", nbttaglist);
+ }
+
+- compoundtag.putBoolean("FallFlying", this.isFallFlying());
+- this.getSleepingPos().ifPresent((blockpos) -> {
+- compoundtag.putInt("SleepingX", blockpos.getX());
+- compoundtag.putInt("SleepingY", blockpos.getY());
+- compoundtag.putInt("SleepingZ", blockpos.getZ());
++ compound.putBoolean("FallFlying", this.isFallFlying());
++ this.getSleepingPos().ifPresent((blockposition) -> {
++ compound.putInt("SleepingX", blockposition.getX());
++ compound.putInt("SleepingY", blockposition.getY());
++ compound.putInt("SleepingZ", blockposition.getZ());
+ });
+ DataResult<Tag> dataresult = this.brain.serializeStart(NbtOps.INSTANCE);
+ Logger logger = LivingEntity.LOGGER;
+
+ java.util.Objects.requireNonNull(logger);
+- dataresult.resultOrPartial(logger::error).ifPresent((tag) -> {
+- compoundtag.put("Brain", tag);
++ dataresult.resultOrPartial(logger::error).ifPresent((nbtbase) -> {
++ compound.put("Brain", nbtbase);
+ });
+ }
+
+ @Override
+- @Override
+- public void readAdditionalSaveData(CompoundTag compoundtag) {
+- this.internalSetAbsorptionAmount(compoundtag.getFloat("AbsorptionAmount"));
+- if (compoundtag.contains("Attributes", 9) && this.level() != null && !this.level().isClientSide) {
+- this.getAttributes().load(compoundtag.getList("Attributes", 10));
++ public void readAdditionalSaveData(CompoundTag compound) {
++ this.internalSetAbsorptionAmount(compound.getFloat("AbsorptionAmount"));
++ if (compound.contains("Attributes", 9) && this.level() != null && !this.level().isClientSide) {
++ this.getAttributes().load(compound.getList("Attributes", 10));
+ }
+
+- if (compoundtag.contains("active_effects", 9)) {
+- ListTag listtag = compoundtag.getList("active_effects", 10);
++ if (compound.contains("active_effects", 9)) {
++ ListTag nbttaglist = compound.getList("active_effects", 10);
+
+- for (int i = 0; i < listtag.size(); ++i) {
+- CompoundTag compoundtag1 = listtag.getCompound(i);
+- MobEffectInstance mobeffectinstance = MobEffectInstance.load(compoundtag1);
++ for (int i = 0; i < nbttaglist.size(); ++i) {
++ CompoundTag nbttagcompound1 = nbttaglist.getCompound(i);
++ MobEffectInstance mobeffect = MobEffectInstance.load(nbttagcompound1);
+
+- if (mobeffectinstance != null) {
+- this.activeEffects.put(mobeffectinstance.getEffect(), mobeffectinstance);
++ if (mobeffect != null) {
++ this.activeEffects.put(mobeffect.getEffect(), mobeffect);
+ }
+ }
+ }
+
+- if (compoundtag.contains("Health", 99)) {
+- this.setHealth(compoundtag.getFloat("Health"));
++ // CraftBukkit start
++ if (compound.contains("Bukkit.MaxHealth")) {
++ Tag nbtbase = compound.get("Bukkit.MaxHealth");
++ if (nbtbase.getId() == 5) {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(((FloatTag) nbtbase).getAsDouble());
++ } else if (nbtbase.getId() == 3) {
++ this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(((IntTag) nbtbase).getAsDouble());
++ }
+ }
++ // CraftBukkit end
+
+- this.hurtTime = compoundtag.getShort("HurtTime");
+- this.deathTime = compoundtag.getShort("DeathTime");
+- this.lastHurtByMobTimestamp = compoundtag.getInt("HurtByTimestamp");
+- if (compoundtag.contains("Team", 8)) {
+- String s = compoundtag.getString("Team");
+- PlayerTeam playerteam = this.level().getScoreboard().getPlayerTeam(s);
+- boolean flag = playerteam != null && this.level().getScoreboard().addPlayerToTeam(this.getStringUUID(), playerteam);
++ if (compound.contains("Health", 99)) {
++ this.setHealth(compound.getFloat("Health"));
++ }
+
++ this.hurtTime = compound.getShort("HurtTime");
++ this.deathTime = compound.getShort("DeathTime");
++ this.lastHurtByMobTimestamp = compound.getInt("HurtByTimestamp");
++ if (compound.contains("Team", 8)) {
++ String s = compound.getString("Team");
++ PlayerTeam scoreboardteam = this.level().getScoreboard().getPlayerTeam(s);
++ boolean flag = scoreboardteam != null && this.level().getScoreboard().addPlayerToTeam(this.getStringUUID(), scoreboardteam);
++
+ if (!flag) {
+ LivingEntity.LOGGER.warn("Unable to add mob to team \"{}\" (that team probably doesn't exist)", s);
+ }
+ }
+
+- if (compoundtag.getBoolean("FallFlying")) {
++ if (compound.getBoolean("FallFlying")) {
+ this.setSharedFlag(7, true);
+ }
+
+- if (compoundtag.contains("SleepingX", 99) && compoundtag.contains("SleepingY", 99) && compoundtag.contains("SleepingZ", 99)) {
+- BlockPos blockpos = new BlockPos(compoundtag.getInt("SleepingX"), compoundtag.getInt("SleepingY"), compoundtag.getInt("SleepingZ"));
++ if (compound.contains("SleepingX", 99) && compound.contains("SleepingY", 99) && compound.contains("SleepingZ", 99)) {
++ BlockPos blockposition = new BlockPos(compound.getInt("SleepingX"), compound.getInt("SleepingY"), compound.getInt("SleepingZ"));
+
+- this.setSleepingPos(blockpos);
+- this.entityData.set(LivingEntity.DATA_POSE, Pose.SLEEPING);
++ this.setSleepingPos(blockposition);
++ this.entityData.set(LivingEntity.DATA_POSE, EntityPose.SLEEPING);
+ if (!this.firstTick) {
+- this.setPosToBed(blockpos);
++ this.setPosToBed(blockposition);
+ }
+ }
+
+- if (compoundtag.contains("Brain", 10)) {
+- this.brain = this.makeBrain(new Dynamic(NbtOps.INSTANCE, compoundtag.get("Brain")));
++ if (compound.contains("Brain", 10)) {
++ this.brain = this.makeBrain(new Dynamic(NbtOps.INSTANCE, compound.get("Brain")));
+ }
+
+ }
+
++ // CraftBukkit start
++ private boolean isTickingEffects = false;
++ private List<ProcessableEffect> effectsToProcess = Lists.newArrayList();
++
++ private static class ProcessableEffect {
++
++ private MobEffect type;
++ private MobEffectInstance effect;
++ private final EntityPotionEffectEvent.Cause cause;
++
++ private ProcessableEffect(MobEffectInstance effect, EntityPotionEffectEvent.Cause cause) {
++ this.effect = effect;
++ this.cause = cause;
++ }
++
++ private ProcessableEffect(MobEffect type, EntityPotionEffectEvent.Cause cause) {
++ this.type = type;
++ this.cause = cause;
++ }
++ }
++ // CraftBukkit end
++
+ protected void tickEffects() {
+ Iterator iterator = this.activeEffects.keySet().iterator();
+
++ isTickingEffects = true; // CraftBukkit
+ try {
+ while (iterator.hasNext()) {
+- MobEffect mobeffect = (MobEffect) iterator.next();
+- MobEffectInstance mobeffectinstance = (MobEffectInstance) this.activeEffects.get(mobeffect);
++ MobEffect mobeffectlist = (MobEffect) iterator.next();
++ MobEffectInstance mobeffect = (MobEffectInstance) this.activeEffects.get(mobeffectlist);
+
+- if (!mobeffectinstance.tick(this, () -> {
+- this.onEffectUpdated(mobeffectinstance, true, (Entity) null);
++ if (!mobeffect.tick(this, () -> {
++ this.onEffectUpdated(mobeffect, true, (Entity) null);
+ })) {
+ if (!this.level().isClientSide) {
++ // CraftBukkit start
++ EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, mobeffect, null, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.EXPIRATION);
++ if (event.isCancelled()) {
++ continue;
++ }
++ // CraftBukkit end
+ iterator.remove();
+- this.onEffectRemoved(mobeffectinstance);
++ this.onEffectRemoved(mobeffect);
+ }
+- } else if (mobeffectinstance.getDuration() % 600 == 0) {
+- this.onEffectUpdated(mobeffectinstance, false, (Entity) null);
++ } else if (mobeffect.getDuration() % 600 == 0) {
++ this.onEffectUpdated(mobeffect, false, (Entity) null);
+ }
+ }
+ } catch (ConcurrentModificationException concurrentmodificationexception) {
+ ;
+ }
++ // CraftBukkit start
++ isTickingEffects = false;
++ for (ProcessableEffect e : effectsToProcess) {
++ if (e.effect != null) {
++ addEffect(e.effect, e.cause);
++ } else {
++ removeEffect(e.type, e.cause);
++ }
++ }
++ effectsToProcess.clear();
++ // CraftBukkit end
+
+ if (this.effectsDirty) {
+ if (!this.level().isClientSide) {
+@@ -880,7 +971,7 @@
+
+ }
+
+- public double getVisibilityPercent(@Nullable Entity entity) {
++ public double getVisibilityPercent(@Nullable Entity lookingEntity) {
+ double d0 = 1.0D;
+
+ if (this.isDiscrete()) {
+@@ -897,11 +988,11 @@
+ d0 *= 0.7D * (double) f;
+ }
+
+- if (entity != null) {
++ if (lookingEntity != null) {
+ ItemStack itemstack = this.getItemBySlot(EquipmentSlot.HEAD);
+- EntityType<?> entitytype = entity.getType();
++ EntityType<?> entitytypes = lookingEntity.getType();
+
+- if (entitytype == EntityType.SKELETON && itemstack.is(Items.SKELETON_SKULL) || entitytype == EntityType.ZOMBIE && itemstack.is(Items.ZOMBIE_HEAD) || entitytype == EntityType.PIGLIN && itemstack.is(Items.PIGLIN_HEAD) || entitytype == EntityType.PIGLIN_BRUTE && itemstack.is(Items.PIGLIN_HEAD) || entitytype == EntityType.CREEPER && itemstack.is(Items.CREEPER_HEAD)) {
++ if (entitytypes == EntityType.SKELETON && itemstack.is(Items.SKELETON_SKULL) || entitytypes == EntityType.ZOMBIE && itemstack.is(Items.ZOMBIE_HEAD) || entitytypes == EntityType.PIGLIN && itemstack.is(Items.PIGLIN_HEAD) || entitytypes == EntityType.PIGLIN_BRUTE && itemstack.is(Items.PIGLIN_HEAD) || entitytypes == EntityType.CREEPER && itemstack.is(Items.CREEPER_HEAD)) {
+ d0 *= 0.5D;
+ }
+ }
+@@ -909,12 +1000,12 @@
+ return d0;
+ }
+
+- public boolean canAttack(LivingEntity livingentity) {
+- return livingentity instanceof Player && this.level().getDifficulty() == Difficulty.PEACEFUL ? false : livingentity.canBeSeenAsEnemy();
++ public boolean canAttack(LivingEntity target) {
++ return target instanceof net.minecraft.world.entity.player.Player && this.level().getDifficulty() == Difficulty.PEACEFUL ? false : target.canBeSeenAsEnemy();
+ }
+
+- public boolean canAttack(LivingEntity livingentity, TargetingConditions targetingconditions) {
+- return targetingconditions.test(this, livingentity);
++ public boolean canAttack(LivingEntity livingentity, TargetingConditions condition) {
++ return condition.test(this, livingentity);
+ }
+
+ public boolean canBeSeenAsEnemy() {
+@@ -925,18 +1016,18 @@
+ return !this.isSpectator() && this.isAlive();
+ }
+
+- public static boolean areAllEffectsAmbient(Collection<MobEffectInstance> collection) {
+- Iterator iterator = collection.iterator();
++ public static boolean areAllEffectsAmbient(Collection<MobEffectInstance> potionEffects) {
++ Iterator iterator = potionEffects.iterator();
+
+- MobEffectInstance mobeffectinstance;
++ MobEffectInstance mobeffect;
+
+ do {
+ if (!iterator.hasNext()) {
+ return true;
+ }
+
+- mobeffectinstance = (MobEffectInstance) iterator.next();
+- } while (!mobeffectinstance.isVisible() || mobeffectinstance.isAmbient());
++ mobeffect = (MobEffectInstance) iterator.next();
++ } while (!mobeffect.isVisible() || mobeffect.isAmbient());
+
+ return false;
+ }
+@@ -946,7 +1037,13 @@
+ this.entityData.set(LivingEntity.DATA_EFFECT_COLOR_ID, 0);
+ }
+
++ // CraftBukkit start
+ public boolean removeAllEffects() {
++ return removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.UNKNOWN);
++ }
++
++ public boolean removeAllEffects(EntityPotionEffectEvent.Cause cause) {
++ // CraftBukkit end
+ if (this.level().isClientSide) {
+ return false;
+ } else {
+@@ -955,7 +1052,14 @@
+ boolean flag;
+
+ for (flag = false; iterator.hasNext(); flag = true) {
+- this.onEffectRemoved((MobEffectInstance) iterator.next());
++ // CraftBukkit start
++ MobEffectInstance effect = (MobEffectInstance) iterator.next();
++ EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, effect, null, cause, EntityPotionEffectEvent.Action.CLEARED);
++ if (event.isCancelled()) {
++ continue;
++ }
++ this.onEffectRemoved(effect);
++ // CraftBukkit end
+ iterator.remove();
+ }
+
+@@ -971,45 +1075,75 @@
+ return this.activeEffects;
+ }
+
+- public boolean hasEffect(MobEffect mobeffect) {
+- return this.activeEffects.containsKey(mobeffect);
++ public boolean hasEffect(MobEffect effect) {
++ return this.activeEffects.containsKey(effect);
+ }
+
+ @Nullable
+- public MobEffectInstance getEffect(MobEffect mobeffect) {
+- return (MobEffectInstance) this.activeEffects.get(mobeffect);
++ public MobEffectInstance getEffect(MobEffect effect) {
++ return (MobEffectInstance) this.activeEffects.get(effect);
+ }
+
+- public final boolean addEffect(MobEffectInstance mobeffectinstance) {
+- return this.addEffect(mobeffectinstance, (Entity) null);
++ public final boolean addEffect(MobEffectInstance effectInstance) {
++ return this.addEffect(effectInstance, (Entity) null);
+ }
+
+- public boolean addEffect(MobEffectInstance mobeffectinstance, @Nullable Entity entity) {
+- if (!this.canBeAffected(mobeffectinstance)) {
++ // CraftBukkit start
++ public boolean addEffect(MobEffectInstance mobeffect, EntityPotionEffectEvent.Cause cause) {
++ return this.addEffect(mobeffect, (Entity) null, cause);
++ }
++
++ public boolean addEffect(MobEffectInstance effectInstance, @Nullable Entity entity) {
++ return this.addEffect(effectInstance, entity, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.UNKNOWN);
++ }
++
++ public boolean addEffect(MobEffectInstance mobeffect, @Nullable Entity entity, EntityPotionEffectEvent.Cause cause) {
++ if (isTickingEffects) {
++ effectsToProcess.add(new ProcessableEffect(mobeffect, cause));
++ return true;
++ }
++ // CraftBukkit end
++
++ if (!this.canBeAffected(mobeffect)) {
+ return false;
+ } else {
+- MobEffectInstance mobeffectinstance1 = (MobEffectInstance) this.activeEffects.get(mobeffectinstance.getEffect());
++ MobEffectInstance mobeffect1 = (MobEffectInstance) this.activeEffects.get(mobeffect.getEffect());
+ boolean flag = false;
+
+- if (mobeffectinstance1 == null) {
+- this.activeEffects.put(mobeffectinstance.getEffect(), mobeffectinstance);
+- this.onEffectAdded(mobeffectinstance, entity);
++ // CraftBukkit start
++ boolean override = false;
++ if (mobeffect1 != null) {
++ override = new MobEffectInstance(mobeffect1).update(mobeffect);
++ }
++
++ EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, mobeffect1, mobeffect, cause, override);
++ if (event.isCancelled()) {
++ return false;
++ }
++ // CraftBukkit end
++
++ if (mobeffect1 == null) {
++ this.activeEffects.put(mobeffect.getEffect(), mobeffect);
++ this.onEffectAdded(mobeffect, entity);
+ flag = true;
+- } else if (mobeffectinstance1.update(mobeffectinstance)) {
+- this.onEffectUpdated(mobeffectinstance1, true, entity);
++ // CraftBukkit start
++ } else if (event.isOverride()) {
++ mobeffect1.update(mobeffect);
++ this.onEffectUpdated(mobeffect1, true, entity);
++ // CraftBukkit end
+ flag = true;
+ }
+
+- mobeffectinstance.onEffectStarted(this);
++ mobeffect.onEffectStarted(this);
+ return flag;
+ }
+ }
+
+- public boolean canBeAffected(MobEffectInstance mobeffectinstance) {
+- if (this.getMobType() == MobType.UNDEAD) {
+- MobEffect mobeffect = mobeffectinstance.getEffect();
++ public boolean canBeAffected(MobEffectInstance effectInstance) {
++ if (this.getMobType() == EnumMonsterType.UNDEAD) {
++ MobEffect mobeffectlist = effectInstance.getEffect();
+
+- if (mobeffect == MobEffects.REGENERATION || mobeffect == MobEffects.POISON) {
++ if (mobeffectlist == MobEffects.REGENERATION || mobeffectlist == MobEffects.POISON) {
+ return false;
+ }
+ }
+@@ -1017,83 +1151,109 @@
+ return true;
+ }
+
+- public void forceAddEffect(MobEffectInstance mobeffectinstance, @Nullable Entity entity) {
+- if (this.canBeAffected(mobeffectinstance)) {
+- MobEffectInstance mobeffectinstance1 = (MobEffectInstance) this.activeEffects.put(mobeffectinstance.getEffect(), mobeffectinstance);
++ public void forceAddEffect(MobEffectInstance instance, @Nullable Entity entity) {
++ if (this.canBeAffected(instance)) {
++ MobEffectInstance mobeffect1 = (MobEffectInstance) this.activeEffects.put(instance.getEffect(), instance);
+
+- if (mobeffectinstance1 == null) {
+- this.onEffectAdded(mobeffectinstance, entity);
++ if (mobeffect1 == null) {
++ this.onEffectAdded(instance, entity);
+ } else {
+- this.onEffectUpdated(mobeffectinstance, true, entity);
++ this.onEffectUpdated(instance, true, entity);
+ }
+
+ }
+ }
+
+ public boolean isInvertedHealAndHarm() {
+- return this.getMobType() == MobType.UNDEAD;
++ return this.getMobType() == EnumMonsterType.UNDEAD;
+ }
+
++ // CraftBukkit start
+ @Nullable
+- public MobEffectInstance removeEffectNoUpdate(@Nullable MobEffect mobeffect) {
+- return (MobEffectInstance) this.activeEffects.remove(mobeffect);
++ public MobEffectInstance removeEffectNoUpdate(@Nullable MobEffect effect) {
++ return c(effect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.UNKNOWN);
+ }
+
+- public boolean removeEffect(MobEffect mobeffect) {
+- MobEffectInstance mobeffectinstance = this.removeEffectNoUpdate(mobeffect);
++ @Nullable
++ public MobEffectInstance c(@Nullable MobEffect mobeffectlist, EntityPotionEffectEvent.Cause cause) {
++ if (isTickingEffects) {
++ effectsToProcess.add(new ProcessableEffect(mobeffectlist, cause));
++ return null;
++ }
+
+- if (mobeffectinstance != null) {
+- this.onEffectRemoved(mobeffectinstance);
++ MobEffectInstance effect = this.activeEffects.get(mobeffectlist);
++ if (effect == null) {
++ return null;
++ }
++
++ EntityPotionEffectEvent event = CraftEventFactory.callEntityPotionEffectChangeEvent(this, effect, null, cause);
++ if (event.isCancelled()) {
++ return null;
++ }
++
++ return (MobEffectInstance) this.activeEffects.remove(mobeffectlist);
++ }
++
++ public boolean removeEffect(MobEffect effect) {
++ return removeEffect(effect, org.bukkit.event.entity.EntityPotionEffectEvent.Cause.UNKNOWN);
++ }
++
++ public boolean removeEffect(MobEffect mobeffectlist, EntityPotionEffectEvent.Cause cause) {
++ MobEffectInstance mobeffect = this.c(mobeffectlist, cause);
++ // CraftBukkit end
++
++ if (mobeffect != null) {
++ this.onEffectRemoved(mobeffect);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+- protected void onEffectAdded(MobEffectInstance mobeffectinstance, @Nullable Entity entity) {
++ protected void onEffectAdded(MobEffectInstance effectInstance, @Nullable Entity entity) {
+ this.effectsDirty = true;
+ if (!this.level().isClientSide) {
+- mobeffectinstance.getEffect().addAttributeModifiers(this.getAttributes(), mobeffectinstance.getAmplifier());
+- this.sendEffectToPassengers(mobeffectinstance);
++ effectInstance.getEffect().addAttributeModifiers(this.getAttributes(), effectInstance.getAmplifier());
++ this.sendEffectToPassengers(effectInstance);
+ }
+
+ }
+
+- public void sendEffectToPassengers(MobEffectInstance mobeffectinstance) {
++ public void sendEffectToPassengers(MobEffectInstance effectInstance) {
+ Iterator iterator = this.getPassengers().iterator();
+
+ while (iterator.hasNext()) {
+ Entity entity = (Entity) iterator.next();
+
+ if (entity instanceof ServerPlayer) {
+- ServerPlayer serverplayer = (ServerPlayer) entity;
++ ServerPlayer entityplayer = (ServerPlayer) entity;
+
+- serverplayer.connection.send(new ClientboundUpdateMobEffectPacket(this.getId(), mobeffectinstance));
++ entityplayer.connection.send(new ClientboundUpdateMobEffectPacket(this.getId(), effectInstance));
+ }
+ }
+
+ }
+
+- protected void onEffectUpdated(MobEffectInstance mobeffectinstance, boolean flag, @Nullable Entity entity) {
++ protected void onEffectUpdated(MobEffectInstance effectInstance, boolean forced, @Nullable Entity entity) {
+ this.effectsDirty = true;
+- if (flag && !this.level().isClientSide) {
+- MobEffect mobeffect = mobeffectinstance.getEffect();
++ if (forced && !this.level().isClientSide) {
++ MobEffect mobeffectlist = effectInstance.getEffect();
+
+- mobeffect.removeAttributeModifiers(this.getAttributes());
+- mobeffect.addAttributeModifiers(this.getAttributes(), mobeffectinstance.getAmplifier());
++ mobeffectlist.removeAttributeModifiers(this.getAttributes());
++ mobeffectlist.addAttributeModifiers(this.getAttributes(), effectInstance.getAmplifier());
+ this.refreshDirtyAttributes();
+ }
+
+ if (!this.level().isClientSide) {
+- this.sendEffectToPassengers(mobeffectinstance);
++ this.sendEffectToPassengers(effectInstance);
+ }
+
+ }
+
+- protected void onEffectRemoved(MobEffectInstance mobeffectinstance) {
++ protected void onEffectRemoved(MobEffectInstance effectInstance) {
+ this.effectsDirty = true;
+ if (!this.level().isClientSide) {
+- mobeffectinstance.getEffect().removeAttributeModifiers(this.getAttributes());
++ effectInstance.getEffect().removeAttributeModifiers(this.getAttributes());
+ this.refreshDirtyAttributes();
+ Iterator iterator = this.getPassengers().iterator();
+
+@@ -1101,9 +1261,9 @@
+ Entity entity = (Entity) iterator.next();
+
+ if (entity instanceof ServerPlayer) {
+- ServerPlayer serverplayer = (ServerPlayer) entity;
++ ServerPlayer entityplayer = (ServerPlayer) entity;
+
+- serverplayer.connection.send(new ClientboundRemoveMobEffectPacket(this.getId(), mobeffectinstance.getEffect()));
++ entityplayer.connection.send(new ClientboundRemoveMobEffectPacket(this.getId(), effectInstance.getEffect()));
+ }
+ }
+ }
+@@ -1114,22 +1274,22 @@
+ Iterator iterator = this.getAttributes().getDirtyAttributes().iterator();
+
+ while (iterator.hasNext()) {
+- AttributeInstance attributeinstance = (AttributeInstance) iterator.next();
++ AttributeInstance attributemodifiable = (AttributeInstance) iterator.next();
+
+- this.onAttributeUpdated(attributeinstance.getAttribute());
++ this.onAttributeUpdated(attributemodifiable.getAttribute());
+ }
+
+ }
+
+- private void onAttributeUpdated(Attribute attribute) {
++ private void onAttributeUpdated(Attribute attributebase) {
+ float f;
+
+- if (attribute == Attributes.MAX_HEALTH) {
++ if (attributebase == Attributes.MAX_HEALTH) {
+ f = this.getMaxHealth();
+ if (this.getHealth() > f) {
+ this.setHealth(f);
+ }
+- } else if (attribute == Attributes.MAX_ABSORPTION) {
++ } else if (attributebase == Attributes.MAX_ABSORPTION) {
+ f = this.getMaxAbsorption();
+ if (this.getAbsorptionAmount() > f) {
+ this.setAbsorptionAmount(f);
+@@ -1138,21 +1298,56 @@
+
+ }
+
+- public void heal(float f) {
++ // CraftBukkit start - Delegate so we can handle providing a reason for health being regained
++ public void heal(float healAmount) {
++ heal(healAmount, EntityRegainHealthEvent.RegainReason.CUSTOM);
++ }
++
++ public void heal(float f, EntityRegainHealthEvent.RegainReason regainReason) {
+ float f1 = this.getHealth();
+
+ if (f1 > 0.0F) {
+- this.setHealth(f1 + f);
++ EntityRegainHealthEvent event = new EntityRegainHealthEvent(this.getBukkitEntity(), f, regainReason);
++ // Suppress during worldgen
++ if (this.valid) {
++ this.level().getCraftServer().getPluginManager().callEvent(event);
++ }
++
++ if (!event.isCancelled()) {
++ this.setHealth((float) (this.getHealth() + event.getAmount()));
++ }
++ // CraftBukkit end
+ }
+
+ }
+
+ public float getHealth() {
++ // CraftBukkit start - Use unscaled health
++ if (this instanceof ServerPlayer) {
++ return (float) ((ServerPlayer) this).getBukkitEntity().getHealth();
++ }
++ // CraftBukkit end
+ return (Float) this.entityData.get(LivingEntity.DATA_HEALTH_ID);
+ }
+
+- public void setHealth(float f) {
+- this.entityData.set(LivingEntity.DATA_HEALTH_ID, Mth.clamp(f, 0.0F, this.getMaxHealth()));
++ public void setHealth(float health) {
++ // CraftBukkit start - Handle scaled health
++ if (this instanceof ServerPlayer) {
++ org.bukkit.craftbukkit.entity.CraftPlayer player = ((ServerPlayer) this).getBukkitEntity();
++ // Squeeze
++ if (health < 0.0F) {
++ player.setRealHealth(0.0D);
++ } else if (health > player.getMaxHealth()) {
++ player.setRealHealth(player.getMaxHealth());
++ } else {
++ player.setRealHealth(health);
++ }
++
++ player.updateScaledHealth(false);
++ return;
++ }
++ // CraftBukkit end
++ this.entityData.set(LivingEntity.DATA_HEALTH_ID, Mth.clamp(health, 0.0F, this.getMaxHealth()));
+ }
+
+ public boolean isDeadOrDying() {
+@@ -1160,15 +1355,14 @@
+ }
+
+ @Override
+- @Override
+- public boolean hurt(DamageSource damagesource, float f) {
+- if (this.isInvulnerableTo(damagesource)) {
++ public boolean hurt(DamageSource source, float amount) {
++ if (this.isInvulnerableTo(source)) {
+ return false;
+ } else if (this.level().isClientSide) {
+ return false;
+- } else if (this.isDeadOrDying()) {
++ } else if (this.isRemoved() || this.dead || this.getHealth() <= 0.0F) { // CraftBukkit - Don't allow entities that got set to dead/killed elsewhere to get damaged and die
+ return false;
+- } else if (damagesource.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) {
++ } else if (source.is(DamageTypeTags.IS_FIRE) && this.hasEffect(MobEffects.FIRE_RESISTANCE)) {
+ return false;
+ } else {
+ if (this.isSleeping() && !this.level().isClientSide) {
+@@ -1176,82 +1370,93 @@
+ }
+
+ this.noActionTime = 0;
+- float f1 = f;
+- boolean flag = false;
++ float f1 = amount;
++ boolean flag = amount > 0.0F && this.isDamageSourceBlocked(source); // Copied from below
+ float f2 = 0.0F;
+
+- if (f > 0.0F && this.isDamageSourceBlocked(damagesource)) {
+- this.hurtCurrentlyUsedShield(f);
+- f2 = f;
+- f = 0.0F;
+- if (!damagesource.is(DamageTypeTags.IS_PROJECTILE)) {
+- Entity entity = damagesource.getDirectEntity();
++ // CraftBukkit - Moved into damageEntity0(DamageSource, float)
++ if (false && amount > 0.0F && this.isDamageSourceBlocked(source)) {
++ this.hurtCurrentlyUsedShield(amount);
++ f2 = amount;
++ amount = 0.0F;
++ if (!source.is(DamageTypeTags.IS_PROJECTILE)) {
++ Entity entity = source.getDirectEntity();
+
+ if (entity instanceof LivingEntity) {
+- LivingEntity livingentity = (LivingEntity) entity;
++ LivingEntity entityliving = (LivingEntity) entity;
+
+- this.blockUsingShield(livingentity);
++ this.blockUsingShield(entityliving);
+ }
+ }
+
+ flag = true;
+ }
+
+- if (damagesource.is(DamageTypeTags.IS_FREEZING) && this.getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) {
+- f *= 5.0F;
++ if (source.is(DamageTypeTags.IS_FREEZING) && this.getType().is(EntityTypeTags.FREEZE_HURTS_EXTRA_TYPES)) {
++ amount *= 5.0F;
+ }
+
+ this.walkAnimation.setSpeed(1.5F);
+ boolean flag1 = true;
+
+- if ((float) this.invulnerableTime > 10.0F && !damagesource.is(DamageTypeTags.BYPASSES_COOLDOWN)) {
+- if (f <= this.lastHurt) {
++ if ((float) this.invulnerableTime > (float) this.invulnerableDuration / 2.0F && !source.is(DamageTypeTags.BYPASSES_COOLDOWN)) { // CraftBukkit - restore use of maxNoDamageTicks
++ if (amount <= this.lastHurt) {
+ return false;
+ }
+
+- this.actuallyHurt(damagesource, f - this.lastHurt);
+- this.lastHurt = f;
++ // CraftBukkit start
++ if (!this.damageEntity0(source, amount - this.lastHurt)) {
++ return false;
++ }
++ // CraftBukkit end
++ this.lastHurt = amount;
+ flag1 = false;
+ } else {
+- this.lastHurt = f;
+- this.invulnerableTime = 20;
+- this.actuallyHurt(damagesource, f);
++ // CraftBukkit start
++ if (!this.damageEntity0(source, amount)) {
++ return false;
++ }
++ this.lastHurt = amount;
++ this.invulnerableTime = this.invulnerableDuration; // CraftBukkit - restore use of maxNoDamageTicks
++ // this.damageEntity0(damagesource, f);
++ // CraftBukkit end
+ this.hurtDuration = 10;
+ this.hurtTime = this.hurtDuration;
+ }
+
+- if (damagesource.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
+- this.hurtHelmet(damagesource, f);
+- f *= 0.75F;
++ // CraftBukkit - Moved into damageEntity0(DamageSource, float)
++ if (false && source.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
++ this.hurtHelmet(source, amount);
++ amount *= 0.75F;
+ }
+
+- Entity entity1 = damagesource.getEntity();
++ Entity entity1 = source.getEntity();
+
+ if (entity1 != null) {
+ if (entity1 instanceof LivingEntity) {
+- LivingEntity livingentity1 = (LivingEntity) entity1;
++ LivingEntity entityliving1 = (LivingEntity) entity1;
+
+- if (!damagesource.is(DamageTypeTags.NO_ANGER)) {
+- this.setLastHurtByMob(livingentity1);
++ if (!source.is(DamageTypeTags.NO_ANGER)) {
++ this.setLastHurtByMob(entityliving1);
+ }
+ }
+
+- if (entity1 instanceof Player) {
+- Player player = (Player) entity1;
++ if (entity1 instanceof net.minecraft.world.entity.player.Player) {
++ net.minecraft.world.entity.player.Player entityhuman = (net.minecraft.world.entity.player.Player) entity1;
+
+ this.lastHurtByPlayerTime = 100;
+- this.lastHurtByPlayer = player;
++ this.lastHurtByPlayer = entityhuman;
+ } else if (entity1 instanceof Wolf) {
+- Wolf wolf = (Wolf) entity1;
++ Wolf entitywolf = (Wolf) entity1;
+
+- if (wolf.isTame()) {
++ if (entitywolf.isTame()) {
+ this.lastHurtByPlayerTime = 100;
+- LivingEntity livingentity2 = wolf.getOwner();
++ LivingEntity entityliving2 = entitywolf.getOwner();
+
+- if (livingentity2 instanceof Player) {
+- Player player1 = (Player) livingentity2;
++ if (entityliving2 instanceof net.minecraft.world.entity.player.Player) {
++ net.minecraft.world.entity.player.Player entityhuman1 = (net.minecraft.world.entity.player.Player) entityliving2;
+
+- this.lastHurtByPlayer = player1;
++ this.lastHurtByPlayer = entityhuman1;
+ } else {
+ this.lastHurtByPlayer = null;
+ }
+@@ -1263,14 +1468,14 @@
+ if (flag) {
+ this.level().broadcastEntityEvent(this, (byte) 29);
+ } else {
+- this.level().broadcastDamageEvent(this, damagesource);
++ this.level().broadcastDamageEvent(this, source);
+ }
+
+- if (!damagesource.is(DamageTypeTags.NO_IMPACT) && (!flag || f > 0.0F)) {
++ if (!source.is(DamageTypeTags.NO_IMPACT) && (!flag || amount > 0.0F)) {
+ this.markHurt();
+ }
+
+- if (entity1 != null && !damagesource.is(DamageTypeTags.NO_KNOCKBACK)) {
++ if (entity1 != null && !source.is(DamageTypeTags.NO_KNOCKBACK)) {
+ double d0 = entity1.getX() - this.getX();
+
+ double d1;
+@@ -1287,86 +1492,101 @@
+ }
+
+ if (this.isDeadOrDying()) {
+- if (!this.checkTotemDeathProtection(damagesource)) {
+- SoundEvent soundevent = this.getDeathSound();
++ if (!this.checkTotemDeathProtection(source)) {
++ SoundEvent soundeffect = this.getDeathSound();
+
+- if (flag1 && soundevent != null) {
+- this.playSound(soundevent, this.getSoundVolume(), this.getVoicePitch());
++ if (flag1 && soundeffect != null) {
++ this.playSound(soundeffect, this.getSoundVolume(), this.getVoicePitch());
+ }
+
+- this.die(damagesource);
++ this.die(source);
+ }
+ } else if (flag1) {
+- this.playHurtSound(damagesource);
++ this.playHurtSound(source);
+ }
+
+- boolean flag2 = !flag || f > 0.0F;
++ boolean flag2 = !flag || amount > 0.0F;
+
+ if (flag2) {
+- this.lastDamageSource = damagesource;
++ this.lastDamageSource = source;
+ this.lastDamageStamp = this.level().getGameTime();
+ }
+
+ if (this instanceof ServerPlayer) {
+- CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer) this, damagesource, f1, f, flag);
++ CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer) this, source, f1, amount, flag);
+ if (f2 > 0.0F && f2 < 3.4028235E37F) {
+ ((ServerPlayer) this).awardStat(Stats.DAMAGE_BLOCKED_BY_SHIELD, Math.round(f2 * 10.0F));
+ }
+ }
+
+ if (entity1 instanceof ServerPlayer) {
+- CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer) entity1, this, damagesource, f1, f, flag);
++ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer) entity1, this, source, f1, amount, flag);
+ }
+
+ return flag2;
+ }
+ }
+
+- protected void blockUsingShield(LivingEntity livingentity) {
+- livingentity.blockedByShield(this);
++ protected void blockUsingShield(LivingEntity attacker) {
++ attacker.blockedByShield(this);
+ }
+
+- protected void blockedByShield(LivingEntity livingentity) {
+- livingentity.knockback(0.5D, livingentity.getX() - this.getX(), livingentity.getZ() - this.getZ());
++ protected void blockedByShield(LivingEntity defender) {
++ defender.knockback(0.5D, defender.getX() - this.getX(), defender.getZ() - this.getZ());
+ }
+
+- private boolean checkTotemDeathProtection(DamageSource damagesource) {
+- if (damagesource.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) {
++ private boolean checkTotemDeathProtection(DamageSource damageSource) {
++ if (damageSource.is(DamageTypeTags.BYPASSES_INVULNERABILITY)) {
+ return false;
+ } else {
+ ItemStack itemstack = null;
+- InteractionHand[] ainteractionhand = InteractionHand.values();
+- int i = ainteractionhand.length;
++ EnumHand[] aenumhand = EnumHand.values();
++ int i = aenumhand.length;
+
++ // CraftBukkit start
++ EnumHand hand = null;
++ ItemStack itemstack1 = ItemStack.EMPTY;
+ for (int j = 0; j < i; ++j) {
+- InteractionHand interactionhand = ainteractionhand[j];
+- ItemStack itemstack1 = this.getItemInHand(interactionhand);
++ EnumHand enumhand = aenumhand[j];
++ itemstack1 = this.getItemInHand(enumhand);
+
+ if (itemstack1.is(Items.TOTEM_OF_UNDYING)) {
++ hand = enumhand; // CraftBukkit
+ itemstack = itemstack1.copy();
+- itemstack1.shrink(1);
++ // itemstack1.subtract(1); // CraftBukkit
+ break;
+ }
+ }
+
+- if (itemstack != null) {
+- if (this instanceof ServerPlayer) {
+- ServerPlayer serverplayer = (ServerPlayer) this;
++ org.bukkit.inventory.EquipmentSlot handSlot = (hand != null) ? org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(hand) : null;
++ EntityResurrectEvent event = new EntityResurrectEvent((org.bukkit.entity.LivingEntity) this.getBukkitEntity(), handSlot);
++ event.setCancelled(itemstack == null);
++ this.level().getCraftServer().getPluginManager().callEvent(event);
+
+- serverplayer.awardStat(Stats.ITEM_USED.get(Items.TOTEM_OF_UNDYING));
+- CriteriaTriggers.USED_TOTEM.trigger(serverplayer, itemstack);
++ if (!event.isCancelled()) {
++ if (!itemstack1.isEmpty()) {
++ itemstack1.shrink(1);
++ }
++ if (itemstack != null && this instanceof ServerPlayer) {
++ // CraftBukkit end
++ ServerPlayer entityplayer = (ServerPlayer) this;
++
++ entityplayer.awardStat(Stats.ITEM_USED.get(Items.TOTEM_OF_UNDYING));
++ CriteriaTriggers.USED_TOTEM.trigger(entityplayer, itemstack);
+ this.gameEvent(GameEvent.ITEM_INTERACT_FINISH);
+ }
+
+ this.setHealth(1.0F);
+- this.removeAllEffects();
+- this.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 900, 1));
+- this.addEffect(new MobEffectInstance(MobEffects.ABSORPTION, 100, 1));
+- this.addEffect(new MobEffectInstance(MobEffects.FIRE_RESISTANCE, 800, 0));
++ // CraftBukkit start
++ this.removeAllEffects(org.bukkit.event.entity.EntityPotionEffectEvent.Cause.TOTEM);
++ this.addEffect(new MobEffectInstance(MobEffects.REGENERATION, 900, 1), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.TOTEM);
++ this.addEffect(new MobEffectInstance(MobEffects.ABSORPTION, 100, 1), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.TOTEM);
++ this.addEffect(new MobEffectInstance(MobEffects.FIRE_RESISTANCE, 800, 0), org.bukkit.event.entity.EntityPotionEffectEvent.Cause.TOTEM);
++ // CraftBukkit end
+ this.level().broadcastEntityEvent(this, (byte) 35);
+ }
+
+- return itemstack != null;
++ return !event.isCancelled();
+ }
+ }
+
+@@ -1379,60 +1599,60 @@
+ return this.lastDamageSource;
+ }
+
+- protected void playHurtSound(DamageSource damagesource) {
+- SoundEvent soundevent = this.getHurtSound(damagesource);
++ protected void playHurtSound(DamageSource source) {
++ SoundEvent soundeffect = this.getHurtSound(source);
+
+- if (soundevent != null) {
+- this.playSound(soundevent, this.getSoundVolume(), this.getVoicePitch());
++ if (soundeffect != null) {
++ this.playSound(soundeffect, this.getSoundVolume(), this.getVoicePitch());
+ }
+
+ }
+
+- public boolean isDamageSourceBlocked(DamageSource damagesource) {
+- Entity entity = damagesource.getDirectEntity();
++ public boolean isDamageSourceBlocked(DamageSource damageSource) {
++ Entity entity = damageSource.getDirectEntity();
+ boolean flag = false;
+
+ if (entity instanceof AbstractArrow) {
+- AbstractArrow abstractarrow = (AbstractArrow) entity;
++ AbstractArrow entityarrow = (AbstractArrow) entity;
+
+- if (abstractarrow.getPierceLevel() > 0) {
++ if (entityarrow.getPierceLevel() > 0) {
+ flag = true;
+ }
+ }
+
+- if (!damagesource.is(DamageTypeTags.BYPASSES_SHIELD) && this.isBlocking() && !flag) {
+- Vec3 vec3 = damagesource.getSourcePosition();
++ if (!damageSource.is(DamageTypeTags.BYPASSES_SHIELD) && this.isBlocking() && !flag) {
++ Vec3 vec3d = damageSource.getSourcePosition();
+
+- if (vec3 != null) {
+- Vec3 vec31 = this.calculateViewVector(0.0F, this.getYHeadRot());
+- Vec3 vec32 = vec3.vectorTo(this.position());
++ if (vec3d != null) {
++ Vec3 vec3d1 = this.calculateViewVector(0.0F, this.getYHeadRot());
++ Vec3 vec3d2 = vec3d.vectorTo(this.position());
+
+- vec32 = (new Vec3(vec32.x, 0.0D, vec32.z)).normalize();
+- return vec32.dot(vec31) < 0.0D;
++ vec3d2 = (new Vec3(vec3d2.x, 0.0D, vec3d2.z)).normalize();
++ return vec3d2.dot(vec3d1) < 0.0D;
+ }
+ }
+
+ return false;
+ }
+
+- private void breakItem(ItemStack itemstack) {
+- if (!itemstack.isEmpty()) {
++ private void breakItem(ItemStack stack) {
++ if (!stack.isEmpty()) {
+ if (!this.isSilent()) {
+ this.level().playLocalSound(this.getX(), this.getY(), this.getZ(), SoundEvents.ITEM_BREAK, this.getSoundSource(), 0.8F, 0.8F + this.level().random.nextFloat() * 0.4F, false);
+ }
+
+- this.spawnItemParticles(itemstack, 5);
++ this.spawnItemParticles(stack, 5);
+ }
+
+ }
+
+- public void die(DamageSource damagesource) {
++ public void die(DamageSource damageSource) {
+ if (!this.isRemoved() && !this.dead) {
+- Entity entity = damagesource.getEntity();
+- LivingEntity livingentity = this.getKillCredit();
++ Entity entity = damageSource.getEntity();
++ LivingEntity entityliving = this.getKillCredit();
+
+- if (this.deathScore >= 0 && livingentity != null) {
+- livingentity.awardKillScore(this, this.deathScore, damagesource);
++ if (this.deathScore >= 0 && entityliving != null) {
++ entityliving.awardKillScore(this, this.deathScore, damageSource);
+ }
+
+ if (this.isSleeping()) {
+@@ -1445,54 +1665,62 @@
+
+ this.dead = true;
+ this.getCombatTracker().recheckStatus();
+- Level level = this.level();
++ Level world = this.level();
+
+- if (level instanceof ServerLevel) {
+- ServerLevel serverlevel = (ServerLevel) level;
++ if (world instanceof ServerLevel) {
++ ServerLevel worldserver = (ServerLevel) world;
+
+- if (entity == null || entity.killedEntity(serverlevel, this)) {
++ if (entity == null || entity.killedEntity(worldserver, this)) {
+ this.gameEvent(GameEvent.ENTITY_DIE);
+- this.dropAllDeathLoot(damagesource);
+- this.createWitherRose(livingentity);
++ this.dropAllDeathLoot(damageSource);
++ this.createWitherRose(entityliving);
+ }
+
+ this.level().broadcastEntityEvent(this, (byte) 3);
+ }
+
+- this.setPose(Pose.DYING);
++ this.setPose(EntityPose.DYING);
+ }
+ }
+
+- protected void createWitherRose(@Nullable LivingEntity livingentity) {
++ protected void createWitherRose(@Nullable LivingEntity entitySource) {
+ if (!this.level().isClientSide) {
+ boolean flag = false;
+
+- if (livingentity instanceof WitherBoss) {
++ if (entitySource instanceof WitherBoss) {
+ if (this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
+- BlockPos blockpos = this.blockPosition();
+- BlockState blockstate = Blocks.WITHER_ROSE.defaultBlockState();
++ BlockPos blockposition = this.blockPosition();
++ IBlockData iblockdata = Blocks.WITHER_ROSE.defaultBlockState();
+
+- if (this.level().getBlockState(blockpos).isAir() && blockstate.canSurvive(this.level(), blockpos)) {
+- this.level().setBlock(blockpos, blockstate, 3);
+- flag = true;
++ if (this.level().getBlockState(blockposition).isAir() && iblockdata.canSurvive(this.level(), blockposition)) {
++ // CraftBukkit start - call EntityBlockFormEvent for Wither Rose
++ flag = org.bukkit.craftbukkit.event.CraftEventFactory.handleBlockFormEvent(this.level(), blockposition, iblockdata, 3, this);
++ // CraftBukkit end
+ }
+ }
+
+ if (!flag) {
+- ItemEntity itementity = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), new ItemStack(Items.WITHER_ROSE));
++ ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), new ItemStack(Items.WITHER_ROSE));
+
+- this.level().addFreshEntity(itementity);
++ // CraftBukkit start
++ org.bukkit.event.entity.EntityDropItemEvent event = new org.bukkit.event.entity.EntityDropItemEvent(this.getBukkitEntity(), (org.bukkit.entity.Item) entityitem.getBukkitEntity());
++ CraftEventFactory.callEvent(event);
++ if (event.isCancelled()) {
++ return;
++ }
++ // CraftBukkit end
++ this.level().addFreshEntity(entityitem);
+ }
+ }
+
+ }
+ }
+
+- protected void dropAllDeathLoot(DamageSource damagesource) {
+- Entity entity = damagesource.getEntity();
++ protected void dropAllDeathLoot(DamageSource damageSource) {
++ Entity entity = damageSource.getEntity();
+ int i;
+
+- if (entity instanceof Player) {
++ if (entity instanceof net.minecraft.world.entity.player.Player) {
+ i = EnchantmentHelper.getMobLooting((LivingEntity) entity);
+ } else {
+ i = 0;
+@@ -1500,25 +1728,44 @@
+
+ boolean flag = this.lastHurtByPlayerTime > 0;
+
++ this.dropEquipment(); // CraftBukkit - from below
+ if (this.shouldDropLoot() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
+- this.dropFromLootTable(damagesource, flag);
+- this.dropCustomDeathLoot(damagesource, i, flag);
++ this.dropFromLootTable(damageSource, flag);
++ this.dropCustomDeathLoot(damageSource, i, flag);
+ }
++ // CraftBukkit start - Call death event
++ CraftEventFactory.callEntityDeathEvent(this, this.drops);
++ this.drops = new ArrayList<>();
++ // CraftBukkit end
+
+- this.dropEquipment();
++ // this.dropInventory();// CraftBukkit - moved up
+ this.dropExperience();
+ }
+
+ protected void dropEquipment() {}
+
+- protected void dropExperience() {
++ // CraftBukkit start
++ public int getExpReward() {
+ if (this.level() instanceof ServerLevel && !this.wasExperienceConsumed() && (this.isAlwaysExperienceDropper() || this.lastHurtByPlayerTime > 0 && this.shouldDropExperience() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT))) {
+- ExperienceOrb.award((ServerLevel) this.level(), this.position(), this.getExperienceReward());
++ int i = this.getExperienceReward();
++ return i;
++ } else {
++ return 0;
+ }
++ }
++ // CraftBukkit end
+
++ protected void dropExperience() {
++ // CraftBukkit start - Update getExpReward() above if the removed if() changes!
++ if (true && !(this instanceof net.minecraft.world.entity.boss.enderdragon.EnderDragon)) { // CraftBukkit - SPIGOT-2420: Special case ender dragon will drop the xp over time
++ ExperienceOrb.award((ServerLevel) this.level(), this.position(), this.expToDrop);
++ this.expToDrop = 0;
++ }
++ // CraftBukkit end
++
+ }
+
+- protected void dropCustomDeathLoot(DamageSource damagesource, int i, boolean flag) {}
++ protected void dropCustomDeathLoot(DamageSource damageSource, int looting, boolean hitByPlayer) {}
+
+ public ResourceLocation getLootTable() {
+ return this.getType().getDefaultLootTable();
+@@ -1528,35 +1775,35 @@
+ return 0L;
+ }
+
+- protected void dropFromLootTable(DamageSource damagesource, boolean flag) {
+- ResourceLocation resourcelocation = this.getLootTable();
+- LootTable loottable = this.level().getServer().getLootData().getLootTable(resourcelocation);
+- LootParams.Builder lootparams_builder = (new LootParams.Builder((ServerLevel) this.level())).withParameter(LootContextParams.THIS_ENTITY, this).withParameter(LootContextParams.ORIGIN, this.position()).withParameter(LootContextParams.DAMAGE_SOURCE, damagesource).withOptionalParameter(LootContextParams.KILLER_ENTITY, damagesource.getEntity()).withOptionalParameter(LootContextParams.DIRECT_KILLER_ENTITY, damagesource.getDirectEntity());
++ protected void dropFromLootTable(DamageSource damageSource, boolean hitByPlayer) {
++ ResourceLocation minecraftkey = this.getLootTable();
++ LootTable loottable = this.level().getServer().getLootData().getLootTable(minecraftkey);
++ LootParams.Builder lootparams_a = (new LootParams.Builder((ServerLevel) this.level())).withParameter(LootContextParams.THIS_ENTITY, this).withParameter(LootContextParams.ORIGIN, this.position()).withParameter(LootContextParams.DAMAGE_SOURCE, damageSource).withOptionalParameter(LootContextParams.KILLER_ENTITY, damageSource.getEntity()).withOptionalParameter(LootContextParams.DIRECT_KILLER_ENTITY, damageSource.getDirectEntity());
+
+- if (flag && this.lastHurtByPlayer != null) {
+- lootparams_builder = lootparams_builder.withParameter(LootContextParams.LAST_DAMAGE_PLAYER, this.lastHurtByPlayer).withLuck(this.lastHurtByPlayer.getLuck());
++ if (hitByPlayer && this.lastHurtByPlayer != null) {
++ lootparams_a = lootparams_a.withParameter(LootContextParams.LAST_DAMAGE_PLAYER, this.lastHurtByPlayer).withLuck(this.lastHurtByPlayer.getLuck());
+ }
+
+- LootParams lootparams = lootparams_builder.create(LootContextParamSets.ENTITY);
++ LootParams lootparams = lootparams_a.create(LootContextParamSets.ENTITY);
+
+ loottable.getRandomItems(lootparams, this.getLootTableSeed(), this::spawnAtLocation);
+ }
+
+- public void knockback(double d0, double d1, double d2) {
+- d0 *= 1.0D - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE);
+- if (d0 > 0.0D) {
++ public void knockback(double strength, double d1, double x) {
++ strength *= 1.0D - this.getAttributeValue(Attributes.KNOCKBACK_RESISTANCE);
++ if (strength > 0.0D) {
+ this.hasImpulse = true;
+- Vec3 vec3 = this.getDeltaMovement();
+- Vec3 vec31 = (new Vec3(d1, 0.0D, d2)).normalize().scale(d0);
++ Vec3 vec3d = this.getDeltaMovement();
++ Vec3 vec3d1 = (new Vec3(d1, 0.0D, x)).normalize().scale(strength);
+
+- this.setDeltaMovement(vec3.x / 2.0D - vec31.x, this.onGround() ? Math.min(0.4D, vec3.y / 2.0D + d0) : vec3.y, vec3.z / 2.0D - vec31.z);
++ this.setDeltaMovement(vec3d.x / 2.0D - vec3d1.x, this.onGround() ? Math.min(0.4D, vec3d.y / 2.0D + strength) : vec3d.y, vec3d.z / 2.0D - vec3d1.z);
+ }
+ }
+
+- public void indicateDamage(double d0, double d1) {}
++ public void indicateDamage(double xDistance, double d1) {}
+
+ @Nullable
+- protected SoundEvent getHurtSound(DamageSource damagesource) {
++ protected SoundEvent getHurtSound(DamageSource damageSource) {
+ return SoundEvents.GENERIC_HURT;
+ }
+
+@@ -1565,8 +1812,8 @@
+ return SoundEvents.GENERIC_DEATH;
+ }
+
+- private SoundEvent getFallDamageSound(int i) {
+- return i > 4 ? this.getFallSounds().big() : this.getFallSounds().small();
++ private SoundEvent getFallDamageSound(int height) {
++ return height > 4 ? this.getFallSounds().big() : this.getFallSounds().small();
+ }
+
+ public void skipDropExperience() {
+@@ -1582,30 +1829,52 @@
+ }
+
+ protected AABB getHitbox() {
+- AABB aabb = this.getBoundingBox();
++ AABB axisalignedbb = this.getBoundingBox();
+ Entity entity = this.getVehicle();
+
+ if (entity != null) {
+- Vec3 vec3 = entity.getPassengerRidingPosition(this);
++ Vec3 vec3d = entity.getPassengerRidingPosition(this);
+
+- return aabb.setMinY(Math.max(vec3.y, aabb.minY));
++ return axisalignedbb.setMinY(Math.max(vec3d.y, axisalignedbb.minY));
+ } else {
+- return aabb;
++ return axisalignedbb;
+ }
+ }
+
+- public LivingEntity.Fallsounds getFallSounds() {
+- return new LivingEntity.Fallsounds(SoundEvents.GENERIC_SMALL_FALL, SoundEvents.GENERIC_BIG_FALL);
++ public LivingEntity.a getFallSounds() {
++ return new LivingEntity.a(SoundEvents.GENERIC_SMALL_FALL, SoundEvents.GENERIC_BIG_FALL);
+ }
+
+- protected SoundEvent getDrinkingSound(ItemStack itemstack) {
+- return itemstack.getDrinkingSound();
++ protected SoundEvent getDrinkingSound(ItemStack stack) {
++ return stack.getDrinkingSound();
+ }
+
+- public SoundEvent getEatingSound(ItemStack itemstack) {
+- return itemstack.getEatingSound();
++ public SoundEvent getEatingSound(ItemStack stack) {
++ return stack.getEatingSound();
+ }
+
++ // CraftBukkit start - Add delegate methods
++ public SoundEvent getHurtSound0(DamageSource damagesource) {
++ return getHurtSound(damagesource);
++ }
++
++ public SoundEvent getDeathSound0() {
++ return getDeathSound();
++ }
++
++ public SoundEvent getFallDamageSound0(int fallHeight) {
++ return getFallDamageSound(fallHeight);
++ }
++
++ public SoundEvent getDrinkingSound0(ItemStack itemstack) {
++ return getDrinkingSound(itemstack);
++ }
++
++ public SoundEvent getEatingSound0(ItemStack itemstack) {
++ return getEatingSound(itemstack);
++ }
++ // CraftBukkit end
++
+ public Optional<BlockPos> getLastClimbablePos() {
+ return this.lastClimbablePos;
+ }
+@@ -1614,14 +1883,14 @@
+ if (this.isSpectator()) {
+ return false;
+ } else {
+- BlockPos blockpos = this.blockPosition();
+- BlockState blockstate = this.getFeetBlockState();
++ BlockPos blockposition = this.blockPosition();
++ IBlockData iblockdata = this.getFeetBlockState();
+
+- if (blockstate.is(BlockTags.CLIMBABLE)) {
+- this.lastClimbablePos = Optional.of(blockpos);
++ if (iblockdata.is(BlockTags.CLIMBABLE)) {
++ this.lastClimbablePos = Optional.of(blockposition);
+ return true;
+- } else if (blockstate.getBlock() instanceof TrapDoorBlock && this.trapdoorUsableAsLadder(blockpos, blockstate)) {
+- this.lastClimbablePos = Optional.of(blockpos);
++ } else if (iblockdata.getBlock() instanceof TrapDoorBlock && this.trapdoorUsableAsLadder(blockposition, iblockdata)) {
++ this.lastClimbablePos = Optional.of(blockposition);
+ return true;
+ } else {
+ return false;
+@@ -1629,11 +1898,11 @@
+ }
+ }
+
+- private boolean trapdoorUsableAsLadder(BlockPos blockpos, BlockState blockstate) {
+- if ((Boolean) blockstate.getValue(TrapDoorBlock.OPEN)) {
+- BlockState blockstate1 = this.level().getBlockState(blockpos.below());
++ private boolean trapdoorUsableAsLadder(BlockPos pos, IBlockData state) {
++ if ((Boolean) state.getValue(TrapDoorBlock.OPEN)) {
++ IBlockData iblockdata1 = this.level().getBlockState(pos.below());
+
+- if (blockstate1.is(Blocks.LADDER) && blockstate1.getValue(LadderBlock.FACING) == blockstate.getValue(TrapDoorBlock.FACING)) {
++ if (iblockdata1.is(Blocks.LADDER) && iblockdata1.getValue(LadderBlock.FACING) == state.getValue(TrapDoorBlock.FACING)) {
+ return true;
+ }
+ }
+@@ -1642,35 +1911,38 @@
+ }
+
+ @Override
+- @Override
+ public boolean isAlive() {
+ return !this.isRemoved() && this.getHealth() > 0.0F;
+ }
+
+ @Override
+- @Override
+- public boolean causeFallDamage(float f, float f1, DamageSource damagesource) {
+- boolean flag = super.causeFallDamage(f, f1, damagesource);
+- int i = this.calculateFallDamage(f, f1);
++ public boolean causeFallDamage(float fallDistance, float multiplier, DamageSource source) {
++ boolean flag = super.causeFallDamage(fallDistance, multiplier, source);
++ int i = this.calculateFallDamage(fallDistance, multiplier);
+
+ if (i > 0) {
++ // CraftBukkit start
++ if (!this.hurt(source, (float) i)) {
++ return true;
++ }
++ // CraftBukkit end
+ this.playSound(this.getFallDamageSound(i), 1.0F, 1.0F);
+ this.playBlockFallSound();
+- this.hurt(damagesource, (float) i);
++ // this.damageEntity(damagesource, (float) i); // CraftBukkit - moved up
+ return true;
+ } else {
+ return flag;
+ }
+ }
+
+- protected int calculateFallDamage(float f, float f1) {
++ protected int calculateFallDamage(float fallDistance, float damageMultiplier) {
+ if (this.getType().is(EntityTypeTags.FALL_DAMAGE_IMMUNE)) {
+ return 0;
+ } else {
+- MobEffectInstance mobeffectinstance = this.getEffect(MobEffects.JUMP);
+- float f2 = mobeffectinstance == null ? 0.0F : (float) (mobeffectinstance.getAmplifier() + 1);
++ MobEffectInstance mobeffect = this.getEffect(MobEffects.JUMP);
++ float f2 = mobeffect == null ? 0.0F : (float) (mobeffect.getAmplifier() + 1);
+
+- return Mth.ceil((f - 3.0F - f2) * f1);
++ return Mth.ceil((fallDistance - 3.0F - f2) * damageMultiplier);
+ }
+ }
+
+@@ -1679,20 +1951,19 @@
+ int i = Mth.floor(this.getX());
+ int j = Mth.floor(this.getY() - 0.20000000298023224D);
+ int k = Mth.floor(this.getZ());
+- BlockState blockstate = this.level().getBlockState(new BlockPos(i, j, k));
++ IBlockData iblockdata = this.level().getBlockState(new BlockPos(i, j, k));
+
+- if (!blockstate.isAir()) {
+- SoundType soundtype = blockstate.getSoundType();
++ if (!iblockdata.isAir()) {
++ SoundType soundeffecttype = iblockdata.getSoundType();
+
+- this.playSound(soundtype.getFallSound(), soundtype.getVolume() * 0.5F, soundtype.getPitch() * 0.75F);
++ this.playSound(soundeffecttype.getFallSound(), soundeffecttype.getVolume() * 0.5F, soundeffecttype.getPitch() * 0.75F);
+ }
+
+ }
+ }
+
+ @Override
+- @Override
+- public void animateHurt(float f) {
++ public void animateHurt(float yaw) {
+ this.hurtDuration = 10;
+ this.hurtTime = this.hurtDuration;
+ }
+@@ -1701,87 +1972,231 @@
+ return Mth.floor(this.getAttributeValue(Attributes.ARMOR));
+ }
+
+- protected void hurtArmor(DamageSource damagesource, float f) {}
++ protected void hurtArmor(DamageSource damageSource, float damageAmount) {}
+
+- protected void hurtHelmet(DamageSource damagesource, float f) {}
++ protected void hurtHelmet(DamageSource damageSource, float damageAmount) {}
+
+- protected void hurtCurrentlyUsedShield(float f) {}
++ protected void hurtCurrentlyUsedShield(float damageAmount) {}
+
+- protected float getDamageAfterArmorAbsorb(DamageSource damagesource, float f) {
+- if (!damagesource.is(DamageTypeTags.BYPASSES_ARMOR)) {
+- this.hurtArmor(damagesource, f);
+- f = CombatRules.getDamageAfterAbsorb(f, (float) this.getArmorValue(), (float) this.getAttributeValue(Attributes.ARMOR_TOUGHNESS));
++ protected float getDamageAfterArmorAbsorb(DamageSource damageSource, float damageAmount) {
++ if (!damageSource.is(DamageTypeTags.BYPASSES_ARMOR)) {
++ // this.hurtArmor(damagesource, f); // CraftBukkit - Moved into damageEntity0(DamageSource, float)
++ damageAmount = CombatRules.getDamageAfterAbsorb(damageAmount, (float) this.getArmorValue(), (float) this.getAttributeValue(Attributes.ARMOR_TOUGHNESS));
+ }
+
+- return f;
++ return damageAmount;
+ }
+
+- protected float getDamageAfterMagicAbsorb(DamageSource damagesource, float f) {
+- if (damagesource.is(DamageTypeTags.BYPASSES_EFFECTS)) {
+- return f;
++ protected float getDamageAfterMagicAbsorb(DamageSource damageSource, float damageAmount) {
++ if (damageSource.is(DamageTypeTags.BYPASSES_EFFECTS)) {
++ return damageAmount;
+ } else {
+ int i;
+
+- if (this.hasEffect(MobEffects.DAMAGE_RESISTANCE) && !damagesource.is(DamageTypeTags.BYPASSES_RESISTANCE)) {
++ // CraftBukkit - Moved to damageEntity0(DamageSource, float)
++ if (false && this.hasEffect(MobEffects.DAMAGE_RESISTANCE) && !damageSource.is(DamageTypeTags.BYPASSES_RESISTANCE)) {
+ i = (this.getEffect(MobEffects.DAMAGE_RESISTANCE).getAmplifier() + 1) * 5;
+ int j = 25 - i;
+- float f1 = f * (float) j;
+- float f2 = f;
++ float f1 = damageAmount * (float) j;
++ float f2 = damageAmount;
+
+- f = Math.max(f1 / 25.0F, 0.0F);
+- float f3 = f2 - f;
++ damageAmount = Math.max(f1 / 25.0F, 0.0F);
++ float f3 = f2 - damageAmount;
+
+ if (f3 > 0.0F && f3 < 3.4028235E37F) {
+ if (this instanceof ServerPlayer) {
+ ((ServerPlayer) this).awardStat(Stats.DAMAGE_RESISTED, Math.round(f3 * 10.0F));
+- } else if (damagesource.getEntity() instanceof ServerPlayer) {
+- ((ServerPlayer) damagesource.getEntity()).awardStat(Stats.DAMAGE_DEALT_RESISTED, Math.round(f3 * 10.0F));
++ } else if (damageSource.getEntity() instanceof ServerPlayer) {
++ ((ServerPlayer) damageSource.getEntity()).awardStat(Stats.DAMAGE_DEALT_RESISTED, Math.round(f3 * 10.0F));
+ }
+ }
+ }
+
+- if (f <= 0.0F) {
++ if (damageAmount <= 0.0F) {
+ return 0.0F;
+- } else if (damagesource.is(DamageTypeTags.BYPASSES_ENCHANTMENTS)) {
+- return f;
++ } else if (damageSource.is(DamageTypeTags.BYPASSES_ENCHANTMENTS)) {
++ return damageAmount;
+ } else {
+- i = EnchantmentHelper.getDamageProtection(this.getArmorSlots(), damagesource);
++ i = EnchantmentHelper.getDamageProtection(this.getArmorSlots(), damageSource);
+ if (i > 0) {
+- f = CombatRules.getDamageAfterMagicAbsorb(f, (float) i);
++ damageAmount = CombatRules.getDamageAfterMagicAbsorb(damageAmount, (float) i);
+ }
+
+- return f;
++ return damageAmount;
+ }
+ }
+ }
+
+- protected void actuallyHurt(DamageSource damagesource, float f) {
+- if (!this.isInvulnerableTo(damagesource)) {
+- f = this.getDamageAfterArmorAbsorb(damagesource, f);
+- f = this.getDamageAfterMagicAbsorb(damagesource, f);
+- float f1 = f;
++ // CraftBukkit start
++ protected boolean damageEntity0(final DamageSource damagesource, float f) { // void -> boolean, add final
++ if (!this.isInvulnerableTo(damagesource)) {
++ final boolean human = this instanceof net.minecraft.world.entity.player.Player;
++ float originalDamage = f;
++ Function<Double, Double> hardHat = new Function<Double, Double>() {
++ @Override
++ public Double apply(Double f) {
++ if (damagesource.is(DamageTypeTags.DAMAGES_HELMET) && !LivingEntity.this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
++ return -(f - (f * 0.75F));
+
+- f = Math.max(f - this.getAbsorptionAmount(), 0.0F);
+- this.setAbsorptionAmount(this.getAbsorptionAmount() - (f1 - f));
+- float f2 = f1 - f;
++ }
++ return -0.0;
++ }
++ };
++ float hardHatModifier = hardHat.apply((double) f).floatValue();
++ f += hardHatModifier;
+
++ Function<Double, Double> blocking = new Function<Double, Double>() {
++ @Override
++ public Double apply(Double f) {
++ return -((LivingEntity.this.isDamageSourceBlocked(damagesource)) ? f : 0.0);
++ }
++ };
++ float blockingModifier = blocking.apply((double) f).floatValue();
++ f += blockingModifier;
++
++ Function<Double, Double> armor = new Function<Double, Double>() {
++ @Override
++ public Double apply(Double f) {
++ return -(f - LivingEntity.this.getDamageAfterArmorAbsorb(damagesource, f.floatValue()));
++ }
++ };
++ float armorModifier = armor.apply((double) f).floatValue();
++ f += armorModifier;
++
++ Function<Double, Double> resistance = new Function<Double, Double>() {
++ @Override
++ public Double apply(Double f) {
++ if (!damagesource.is(DamageTypeTags.BYPASSES_EFFECTS) && LivingEntity.this.hasEffect(MobEffects.DAMAGE_RESISTANCE) && !damagesource.is(DamageTypeTags.BYPASSES_RESISTANCE)) {
++ int i = (LivingEntity.this.getEffect(MobEffects.DAMAGE_RESISTANCE).getAmplifier() + 1) * 5;
++ int j = 25 - i;
++ float f1 = f.floatValue() * (float) j;
++ return -(f - (f1 / 25.0F));
++ }
++ return -0.0;
++ }
++ };
++ float resistanceModifier = resistance.apply((double) f).floatValue();
++ f += resistanceModifier;
++
++ Function<Double, Double> magic = new Function<Double, Double>() {
++ @Override
++ public Double apply(Double f) {
++ return -(f - LivingEntity.this.getDamageAfterMagicAbsorb(damagesource, f.floatValue()));
++ }
++ };
++ float magicModifier = magic.apply((double) f).floatValue();
++ f += magicModifier;
++
++ Function<Double, Double> absorption = new Function<Double, Double>() {
++ @Override
++ public Double apply(Double f) {
++ return -(Math.max(f - Math.max(f - LivingEntity.this.getAbsorptionAmount(), 0.0F), 0.0F));
++ }
++ };
++ float absorptionModifier = absorption.apply((double) f).floatValue();
++
++ EntityDamageEvent event = CraftEventFactory.handleLivingEntityDamageEvent(this, damagesource, originalDamage, hardHatModifier, blockingModifier, armorModifier, resistanceModifier, magicModifier, absorptionModifier, hardHat, blocking, armor, resistance, magic, absorption);
++ if (damagesource.getEntity() instanceof net.minecraft.world.entity.player.Player) {
++ ((net.minecraft.world.entity.player.Player) damagesource.getEntity()).resetAttackStrengthTicker(); // Moved from EntityHuman in order to make the cooldown reset get called after the damage event is fired
++ }
++ if (event.isCancelled()) {
++ return false;
++ }
++
++ f = (float) event.getFinalDamage();
++
++ // Resistance
++ if (event.getDamage(DamageModifier.RESISTANCE) < 0) {
++ float f3 = (float) -event.getDamage(DamageModifier.RESISTANCE);
++ if (f3 > 0.0F && f3 < 3.4028235E37F) {
++ if (this instanceof ServerPlayer) {
++ ((ServerPlayer) this).awardStat(Stats.DAMAGE_RESISTED, Math.round(f3 * 10.0F));
++ } else if (damagesource.getEntity() instanceof ServerPlayer) {
++ ((ServerPlayer) damagesource.getEntity()).awardStat(Stats.DAMAGE_DEALT_RESISTED, Math.round(f3 * 10.0F));
++ }
++ }
++ }
++
++ // Apply damage to helmet
++ if (damagesource.is(DamageTypeTags.DAMAGES_HELMET) && !this.getItemBySlot(EquipmentSlot.HEAD).isEmpty()) {
++ this.hurtHelmet(damagesource, f);
++ }
++
++ // Apply damage to armor
++ if (!damagesource.is(DamageTypeTags.BYPASSES_ARMOR)) {
++ float armorDamage = (float) (event.getDamage() + event.getDamage(DamageModifier.BLOCKING) + event.getDamage(DamageModifier.HARD_HAT));
++ this.hurtArmor(damagesource, armorDamage);
++ }
++
++ // Apply blocking code // PAIL: steal from above
++ if (event.getDamage(DamageModifier.BLOCKING) < 0) {
++ this.level().broadcastEntityEvent(this, (byte) 29); // SPIGOT-4635 - shield damage sound
++ this.hurtCurrentlyUsedShield((float) -event.getDamage(DamageModifier.BLOCKING));
++ Entity entity = damagesource.getDirectEntity();
++
++ if (entity instanceof LivingEntity) {
++ this.blockUsingShield((LivingEntity) entity);
++ }
++ }
++
++ absorptionModifier = (float) -event.getDamage(DamageModifier.ABSORPTION);
++ this.setAbsorptionAmount(Math.max(this.getAbsorptionAmount() - absorptionModifier, 0.0F));
++ float f2 = absorptionModifier;
++
++ if (f2 > 0.0F && f2 < 3.4028235E37F && this instanceof net.minecraft.world.entity.player.Player) {
++ ((net.minecraft.world.entity.player.Player) this).awardStat(Stats.DAMAGE_ABSORBED, Math.round(f2 * 10.0F));
++ }
+ if (f2 > 0.0F && f2 < 3.4028235E37F) {
+ Entity entity = damagesource.getEntity();
+
+ if (entity instanceof ServerPlayer) {
+- ServerPlayer serverplayer = (ServerPlayer) entity;
++ ServerPlayer entityplayer = (ServerPlayer) entity;
+
+- serverplayer.awardStat(Stats.DAMAGE_DEALT_ABSORBED, Math.round(f2 * 10.0F));
++ entityplayer.awardStat(Stats.DAMAGE_DEALT_ABSORBED, Math.round(f2 * 10.0F));
+ }
+ }
+
+- if (f != 0.0F) {
++ if (f > 0 || !human) {
++ if (human) {
++ // PAIL: Be sure to drag all this code from the EntityHuman subclass each update.
++ ((net.minecraft.world.entity.player.Player) this).causeFoodExhaustion(damagesource.getFoodExhaustion(), org.bukkit.event.entity.EntityExhaustionEvent.ExhaustionReason.DAMAGED); // CraftBukkit - EntityExhaustionEvent
++ if (f < 3.4028235E37F) {
++ ((net.minecraft.world.entity.player.Player) this).awardStat(Stats.DAMAGE_TAKEN, Math.round(f * 10.0F));
++ }
++ }
++ // CraftBukkit end
+ this.getCombatTracker().recordDamage(damagesource, f);
+ this.setHealth(this.getHealth() - f);
+- this.setAbsorptionAmount(this.getAbsorptionAmount() - f);
++ // CraftBukkit start
++ if (!human) {
++ this.setAbsorptionAmount(this.getAbsorptionAmount() - f);
++ }
+ this.gameEvent(GameEvent.ENTITY_DAMAGE);
++
++ return true;
++ } else {
++ // Duplicate triggers if blocking
++ if (event.getDamage(DamageModifier.BLOCKING) < 0) {
++ if (this instanceof ServerPlayer) {
++ CriteriaTriggers.ENTITY_HURT_PLAYER.trigger((ServerPlayer) this, damagesource, f, originalDamage, true);
++ f2 = (float) -event.getDamage(DamageModifier.BLOCKING);
++ if (f2 > 0.0F && f2 < 3.4028235E37F) {
++ ((ServerPlayer) this).awardStat(Stats.DAMAGE_BLOCKED_BY_SHIELD, Math.round(originalDamage * 10.0F));
++ }
++ }
++
++ if (damagesource.getEntity() instanceof ServerPlayer) {
++ CriteriaTriggers.PLAYER_HURT_ENTITY.trigger((ServerPlayer) damagesource.getEntity(), this, damagesource, f, originalDamage, true);
++ }
++
++ return false;
++ } else {
++ return originalDamage > 0;
++ }
++ // CraftBukkit end
+ }
+ }
++ return false; // CraftBukkit
+ }
+
+ public CombatTracker getCombatTracker() {
+@@ -1805,39 +2220,49 @@
+ return (Integer) this.entityData.get(LivingEntity.DATA_ARROW_COUNT_ID);
+ }
+
+- public final void setArrowCount(int i) {
+- this.entityData.set(LivingEntity.DATA_ARROW_COUNT_ID, i);
++ public final void setArrowCount(int count) {
++ // CraftBukkit start
++ setArrowCount(count, false);
+ }
+
++ public final void setArrowCount(int i, boolean flag) {
++ ArrowBodyCountChangeEvent event = CraftEventFactory.callArrowBodyCountChangeEvent(this, getArrowCount(), i, flag);
++ if (event.isCancelled()) {
++ return;
++ }
++ this.entityData.set(LivingEntity.DATA_ARROW_COUNT_ID, event.getNewAmount());
++ }
++ // CraftBukkit end
++
+ public final int getStingerCount() {
+ return (Integer) this.entityData.get(LivingEntity.DATA_STINGER_COUNT_ID);
+ }
+
+- public final void setStingerCount(int i) {
+- this.entityData.set(LivingEntity.DATA_STINGER_COUNT_ID, i);
++ public final void setStingerCount(int stingerCount) {
++ this.entityData.set(LivingEntity.DATA_STINGER_COUNT_ID, stingerCount);
+ }
+
+ private int getCurrentSwingDuration() {
+ return MobEffectUtil.hasDigSpeed(this) ? 6 - (1 + MobEffectUtil.getDigSpeedAmplification(this)) : (this.hasEffect(MobEffects.DIG_SLOWDOWN) ? 6 + (1 + this.getEffect(MobEffects.DIG_SLOWDOWN).getAmplifier()) * 2 : 6);
+ }
+
+- public void swing(InteractionHand interactionhand) {
+- this.swing(interactionhand, false);
++ public void swing(EnumHand hand) {
++ this.swing(hand, false);
+ }
+
+- public void swing(InteractionHand interactionhand, boolean flag) {
++ public void swing(EnumHand hand, boolean updateSelf) {
+ if (!this.swinging || this.swingTime >= this.getCurrentSwingDuration() / 2 || this.swingTime < 0) {
+ this.swingTime = -1;
+ this.swinging = true;
+- this.swingingArm = interactionhand;
++ this.swingingArm = hand;
+ if (this.level() instanceof ServerLevel) {
+- ClientboundAnimatePacket clientboundanimatepacket = new ClientboundAnimatePacket(this, interactionhand == InteractionHand.MAIN_HAND ? 0 : 3);
+- ServerChunkCache serverchunkcache = ((ServerLevel) this.level()).getChunkSource();
++ ClientboundAnimatePacket packetplayoutanimation = new ClientboundAnimatePacket(this, hand == EnumHand.MAIN_HAND ? 0 : 3);
++ ServerChunkCache chunkproviderserver = ((ServerLevel) this.level()).getChunkSource();
+
+- if (flag) {
+- serverchunkcache.broadcastAndSend(this, clientboundanimatepacket);
++ if (updateSelf) {
++ chunkproviderserver.broadcastAndSend(this, packetplayoutanimation);
+ } else {
+- serverchunkcache.broadcast(this, clientboundanimatepacket);
++ chunkproviderserver.broadcast(this, packetplayoutanimation);
+ }
+ }
+ }
+@@ -1845,35 +2270,33 @@
+ }
+
+ @Override
+- @Override
+- public void handleDamageEvent(DamageSource damagesource) {
++ public void handleDamageEvent(DamageSource damageSource) {
+ this.walkAnimation.setSpeed(1.5F);
+ this.invulnerableTime = 20;
+ this.hurtDuration = 10;
+ this.hurtTime = this.hurtDuration;
+- SoundEvent soundevent = this.getHurtSound(damagesource);
++ SoundEvent soundeffect = this.getHurtSound(damageSource);
+
+- if (soundevent != null) {
+- this.playSound(soundevent, this.getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F);
++ if (soundeffect != null) {
++ this.playSound(soundeffect, this.getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F);
+ }
+
+ this.hurt(this.damageSources().generic(), 0.0F);
+- this.lastDamageSource = damagesource;
++ this.lastDamageSource = damageSource;
+ this.lastDamageStamp = this.level().getGameTime();
+ }
+
+ @Override
+- @Override
+- public void handleEntityEvent(byte b0) {
+- switch (b0) {
++ public void handleEntityEvent(byte id) {
++ switch (id) {
+ case 3:
+- SoundEvent soundevent = this.getDeathSound();
++ SoundEvent soundeffect = this.getDeathSound();
+
+- if (soundevent != null) {
+- this.playSound(soundevent, this.getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F);
++ if (soundeffect != null) {
++ this.playSound(soundeffect, this.getSoundVolume(), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F);
+ }
+
+- if (!(this instanceof Player)) {
++ if (!(this instanceof net.minecraft.world.entity.player.Player)) {
+ this.setHealth(0.0F);
+ this.die(this.damageSources().generic());
+ }
+@@ -1928,7 +2351,7 @@
+ this.makePoofParticles();
+ break;
+ default:
+- super.handleEntityEvent(b0);
++ super.handleEntityEvent(id);
+ }
+
+ }
+@@ -1952,7 +2375,6 @@
+ }
+
+ @Override
+- @Override
+ protected void onBelowWorld() {
+ this.hurt(this.damageSources().fellOutOfWorld(), 4.0F);
+ }
+@@ -1978,16 +2400,16 @@
+ return this.getAttributes().getInstance(attribute);
+ }
+
+- public double getAttributeValue(Holder<Attribute> holder) {
+- return this.getAttributeValue((Attribute) holder.value());
++ public double getAttributeValue(Holder<Attribute> attribute) {
++ return this.getAttributeValue((Attribute) attribute.value());
+ }
+
+ public double getAttributeValue(Attribute attribute) {
+ return this.getAttributes().getValue(attribute);
+ }
+
+- public double getAttributeBaseValue(Holder<Attribute> holder) {
+- return this.getAttributeBaseValue((Attribute) holder.value());
++ public double getAttributeBaseValue(Holder<Attribute> attribute) {
++ return this.getAttributeBaseValue((Attribute) attribute.value());
+ }
+
+ public double getAttributeBaseValue(Attribute attribute) {
+@@ -1998,8 +2420,8 @@
+ return this.attributes;
+ }
+
+- public MobType getMobType() {
+- return MobType.UNDEFINED;
++ public EnumMonsterType getMobType() {
++ return EnumMonsterType.UNDEFINED;
+ }
+
+ public ItemStack getMainHandItem() {
+@@ -2020,48 +2442,52 @@
+ return predicate.test(this.getMainHandItem()) || predicate.test(this.getOffhandItem());
+ }
+
+- public ItemStack getItemInHand(InteractionHand interactionhand) {
+- if (interactionhand == InteractionHand.MAIN_HAND) {
++ public ItemStack getItemInHand(EnumHand hand) {
++ if (hand == EnumHand.MAIN_HAND) {
+ return this.getItemBySlot(EquipmentSlot.MAINHAND);
+- } else if (interactionhand == InteractionHand.OFF_HAND) {
++ } else if (hand == EnumHand.OFF_HAND) {
+ return this.getItemBySlot(EquipmentSlot.OFFHAND);
+ } else {
+- throw new IllegalArgumentException("Invalid hand " + interactionhand);
++ throw new IllegalArgumentException("Invalid hand " + hand);
+ }
+ }
+
+- public void setItemInHand(InteractionHand interactionhand, ItemStack itemstack) {
+- if (interactionhand == InteractionHand.MAIN_HAND) {
+- this.setItemSlot(EquipmentSlot.MAINHAND, itemstack);
++ public void setItemInHand(EnumHand hand, ItemStack stack) {
++ if (hand == EnumHand.MAIN_HAND) {
++ this.setItemSlot(EquipmentSlot.MAINHAND, stack);
+ } else {
+- if (interactionhand != InteractionHand.OFF_HAND) {
+- throw new IllegalArgumentException("Invalid hand " + interactionhand);
++ if (hand != EnumHand.OFF_HAND) {
++ throw new IllegalArgumentException("Invalid hand " + hand);
+ }
+
+- this.setItemSlot(EquipmentSlot.OFFHAND, itemstack);
++ this.setItemSlot(EquipmentSlot.OFFHAND, stack);
+ }
+
+ }
+
+- public boolean hasItemInSlot(EquipmentSlot equipmentslot) {
+- return !this.getItemBySlot(equipmentslot).isEmpty();
++ public boolean hasItemInSlot(EquipmentSlot slot) {
++ return !this.getItemBySlot(slot).isEmpty();
+ }
+
+ @Override
+- @Override
+ public abstract Iterable<ItemStack> getArmorSlots();
+
+ public abstract ItemStack getItemBySlot(EquipmentSlot slot);
+
++ // CraftBukkit start
++ public void setItemSlot(EquipmentSlot enumitemslot, ItemStack itemstack, boolean silent) {
++ this.setItemSlot(enumitemslot, itemstack);
++ }
++ // CraftBukkit end
++
+ @Override
+- @Override
+ public abstract void setItemSlot(EquipmentSlot slot, ItemStack stack);
+
+- protected void verifyEquippedItem(ItemStack itemstack) {
+- CompoundTag compoundtag = itemstack.getTag();
++ protected void verifyEquippedItem(ItemStack stack) {
++ CompoundTag nbttagcompound = stack.getTag();
+
+- if (compoundtag != null) {
+- itemstack.getItem().verifyTagAfterLoad(compoundtag);
++ if (nbttagcompound != null) {
++ stack.getItem().verifyTagAfterLoad(nbttagcompound);
+ }
+
+ }
+@@ -2083,14 +2509,13 @@
+ }
+
+ @Override
+- @Override
+- public void setSprinting(boolean flag) {
+- super.setSprinting(flag);
+- AttributeInstance attributeinstance = this.getAttribute(Attributes.MOVEMENT_SPEED);
++ public void setSprinting(boolean sprinting) {
++ super.setSprinting(sprinting);
++ AttributeInstance attributemodifiable = this.getAttribute(Attributes.MOVEMENT_SPEED);
+
+- attributeinstance.removeModifier(LivingEntity.SPEED_MODIFIER_SPRINTING.getId());
+- if (flag) {
+- attributeinstance.addTransientModifier(LivingEntity.SPEED_MODIFIER_SPRINTING);
++ attributemodifiable.removeModifier(LivingEntity.SPEED_MODIFIER_SPRINTING.getId());
++ if (sprinting) {
++ attributemodifiable.addTransientModifier(LivingEntity.SPEED_MODIFIER_SPRINTING);
+ }
+
+ }
+@@ -2108,7 +2533,6 @@
+ }
+
+ @Override
+- @Override
+ public void push(Entity entity) {
+ if (!this.isSleeping()) {
+ super.push(entity);
+@@ -2116,24 +2540,23 @@
+
+ }
+
+- private void dismountVehicle(Entity entity) {
+- Vec3 vec3;
++ private void dismountVehicle(Entity vehicle) {
++ Vec3 vec3d;
+
+ if (this.isRemoved()) {
+- vec3 = this.position();
+- } else if (!entity.isRemoved() && !this.level().getBlockState(entity.blockPosition()).is(BlockTags.PORTALS)) {
+- vec3 = entity.getDismountLocationForPassenger(this);
++ vec3d = this.position();
++ } else if (!vehicle.isRemoved() && !this.level().getBlockState(vehicle.blockPosition()).is(BlockTags.PORTALS)) {
++ vec3d = vehicle.getDismountLocationForPassenger(this);
+ } else {
+- double d0 = Math.max(this.getY(), entity.getY());
++ double d0 = Math.max(this.getY(), vehicle.getY());
+
+- vec3 = new Vec3(this.getX(), d0, this.getZ());
++ vec3d = new Vec3(this.getX(), d0, this.getZ());
+ }
+
+- this.dismountTo(vec3.x, vec3.y, vec3.z);
++ this.dismountTo(vec3d.x, vec3d.y, vec3d.z);
+ }
+
+ @Override
+- @Override
+ public boolean shouldShowName() {
+ return this.isCustomNameVisible();
+ }
+@@ -2147,9 +2570,9 @@
+ }
+
+ protected void jumpFromGround() {
+- Vec3 vec3 = this.getDeltaMovement();
++ Vec3 vec3d = this.getDeltaMovement();
+
+- this.setDeltaMovement(vec3.x, (double) this.getJumpPower(), vec3.z);
++ this.setDeltaMovement(vec3d.x, (double) this.getJumpPower(), vec3d.z);
+ if (this.isSprinting()) {
+ float f = this.getYRot() * 0.017453292F;
+
+@@ -2163,7 +2586,7 @@
+ this.setDeltaMovement(this.getDeltaMovement().add(0.0D, -0.03999999910593033D, 0.0D));
+ }
+
+- protected void jumpInLiquid(TagKey<Fluid> tagkey) {
++ protected void jumpInLiquid(TagKey<Fluid> fluidTag) {
+ this.setDeltaMovement(this.getDeltaMovement().add(0.0D, 0.03999999910593033D, 0.0D));
+ }
+
+@@ -2171,11 +2594,11 @@
+ return 0.8F;
+ }
+
+- public boolean canStandOnFluid(FluidState fluidstate) {
++ public boolean canStandOnFluid(FluidState fluidState) {
+ return false;
+ }
+
+- public void travel(Vec3 vec3) {
++ public void travel(Vec3 travelVector) {
+ if (this.isControlledByLocalInstance()) {
+ double d0 = 0.08D;
+ boolean flag = this.getDeltaMovement().y <= 0.0D;
+@@ -2184,11 +2607,11 @@
+ d0 = 0.01D;
+ }
+
+- FluidState fluidstate = this.level().getFluidState(this.blockPosition());
++ FluidState fluid = this.level().getFluidState(this.blockPosition());
+ double d1;
+ float f;
+
+- if (this.isInWater() && this.isAffectedByFluids() && !this.canStandOnFluid(fluidstate)) {
++ if (this.isInWater() && this.isAffectedByFluids() && !this.canStandOnFluid(fluid)) {
+ d1 = this.getY();
+ f = this.isSprinting() ? 0.9F : this.getWaterSlowDown();
+ float f1 = 0.02F;
+@@ -2211,31 +2634,31 @@
+ f = 0.96F;
+ }
+
+- this.moveRelative(f1, vec3);
+- this.move(MoverType.SELF, this.getDeltaMovement());
+- Vec3 vec31 = this.getDeltaMovement();
++ this.moveRelative(f1, travelVector);
++ this.move(EnumMoveType.SELF, this.getDeltaMovement());
++ Vec3 vec3d1 = this.getDeltaMovement();
+
+ if (this.horizontalCollision && this.onClimbable()) {
+- vec31 = new Vec3(vec31.x, 0.2D, vec31.z);
++ vec3d1 = new Vec3(vec3d1.x, 0.2D, vec3d1.z);
+ }
+
+- this.setDeltaMovement(vec31.multiply((double) f, 0.800000011920929D, (double) f));
+- Vec3 vec32 = this.getFluidFallingAdjustedMovement(d0, flag, this.getDeltaMovement());
++ this.setDeltaMovement(vec3d1.multiply((double) f, 0.800000011920929D, (double) f));
++ Vec3 vec3d2 = this.getFluidFallingAdjustedMovement(d0, flag, this.getDeltaMovement());
+
+- this.setDeltaMovement(vec32);
+- if (this.horizontalCollision && this.isFree(vec32.x, vec32.y + 0.6000000238418579D - this.getY() + d1, vec32.z)) {
+- this.setDeltaMovement(vec32.x, 0.30000001192092896D, vec32.z);
++ this.setDeltaMovement(vec3d2);
++ if (this.horizontalCollision && this.isFree(vec3d2.x, vec3d2.y + 0.6000000238418579D - this.getY() + d1, vec3d2.z)) {
++ this.setDeltaMovement(vec3d2.x, 0.30000001192092896D, vec3d2.z);
+ }
+- } else if (this.isInLava() && this.isAffectedByFluids() && !this.canStandOnFluid(fluidstate)) {
++ } else if (this.isInLava() && this.isAffectedByFluids() && !this.canStandOnFluid(fluid)) {
+ d1 = this.getY();
+- this.moveRelative(0.02F, vec3);
+- this.move(MoverType.SELF, this.getDeltaMovement());
+- Vec3 vec33;
++ this.moveRelative(0.02F, travelVector);
++ this.move(EnumMoveType.SELF, this.getDeltaMovement());
++ Vec3 vec3d3;
+
+ if (this.getFluidHeight(FluidTags.LAVA) <= this.getFluidJumpThreshold()) {
+ this.setDeltaMovement(this.getDeltaMovement().multiply(0.5D, 0.800000011920929D, 0.5D));
+- vec33 = this.getFluidFallingAdjustedMovement(d0, flag, this.getDeltaMovement());
+- this.setDeltaMovement(vec33);
++ vec3d3 = this.getFluidFallingAdjustedMovement(d0, flag, this.getDeltaMovement());
++ this.setDeltaMovement(vec3d3);
+ } else {
+ this.setDeltaMovement(this.getDeltaMovement().scale(0.5D));
+ }
+@@ -2244,41 +2667,41 @@
+ this.setDeltaMovement(this.getDeltaMovement().add(0.0D, -d0 / 4.0D, 0.0D));
+ }
+
+- vec33 = this.getDeltaMovement();
+- if (this.horizontalCollision && this.isFree(vec33.x, vec33.y + 0.6000000238418579D - this.getY() + d1, vec33.z)) {
+- this.setDeltaMovement(vec33.x, 0.30000001192092896D, vec33.z);
++ vec3d3 = this.getDeltaMovement();
++ if (this.horizontalCollision && this.isFree(vec3d3.x, vec3d3.y + 0.6000000238418579D - this.getY() + d1, vec3d3.z)) {
++ this.setDeltaMovement(vec3d3.x, 0.30000001192092896D, vec3d3.z);
+ }
+ } else if (this.isFallFlying()) {
+ this.checkSlowFallDistance();
+- Vec3 vec34 = this.getDeltaMovement();
+- Vec3 vec35 = this.getLookAngle();
++ Vec3 vec3d4 = this.getDeltaMovement();
++ Vec3 vec3d5 = this.getLookAngle();
+
+ f = this.getXRot() * 0.017453292F;
+- double d2 = Math.sqrt(vec35.x * vec35.x + vec35.z * vec35.z);
+- double d3 = vec34.horizontalDistance();
+- double d4 = vec35.length();
++ double d2 = Math.sqrt(vec3d5.x * vec3d5.x + vec3d5.z * vec3d5.z);
++ double d3 = vec3d4.horizontalDistance();
++ double d4 = vec3d5.length();
+ double d5 = Math.cos((double) f);
+
+ d5 = d5 * d5 * Math.min(1.0D, d4 / 0.4D);
+- vec34 = this.getDeltaMovement().add(0.0D, d0 * (-1.0D + d5 * 0.75D), 0.0D);
++ vec3d4 = this.getDeltaMovement().add(0.0D, d0 * (-1.0D + d5 * 0.75D), 0.0D);
+ double d6;
+
+- if (vec34.y < 0.0D && d2 > 0.0D) {
+- d6 = vec34.y * -0.1D * d5;
+- vec34 = vec34.add(vec35.x * d6 / d2, d6, vec35.z * d6 / d2);
++ if (vec3d4.y < 0.0D && d2 > 0.0D) {
++ d6 = vec3d4.y * -0.1D * d5;
++ vec3d4 = vec3d4.add(vec3d5.x * d6 / d2, d6, vec3d5.z * d6 / d2);
+ }
+
+ if (f < 0.0F && d2 > 0.0D) {
+ d6 = d3 * (double) (-Mth.sin(f)) * 0.04D;
+- vec34 = vec34.add(-vec35.x * d6 / d2, d6 * 3.2D, -vec35.z * d6 / d2);
++ vec3d4 = vec3d4.add(-vec3d5.x * d6 / d2, d6 * 3.2D, -vec3d5.z * d6 / d2);
+ }
+
+ if (d2 > 0.0D) {
+- vec34 = vec34.add((vec35.x / d2 * d3 - vec34.x) * 0.1D, 0.0D, (vec35.z / d2 * d3 - vec34.z) * 0.1D);
++ vec3d4 = vec3d4.add((vec3d5.x / d2 * d3 - vec3d4.x) * 0.1D, 0.0D, (vec3d5.z / d2 * d3 - vec3d4.z) * 0.1D);
+ }
+
+- this.setDeltaMovement(vec34.multiply(0.9900000095367432D, 0.9800000190734863D, 0.9900000095367432D));
+- this.move(MoverType.SELF, this.getDeltaMovement());
++ this.setDeltaMovement(vec3d4.multiply(0.9900000095367432D, 0.9800000190734863D, 0.9900000095367432D));
++ this.move(EnumMoveType.SELF, this.getDeltaMovement());
+ if (this.horizontalCollision && !this.level().isClientSide) {
+ d6 = this.getDeltaMovement().horizontalDistance();
+ double d7 = d3 - d6;
+@@ -2291,19 +2714,20 @@
+ }
+
+ if (this.onGround() && !this.level().isClientSide) {
++ if (getSharedFlag(7) && !CraftEventFactory.callToggleGlideEvent(this, false).isCancelled()) // CraftBukkit
+ this.setSharedFlag(7, false);
+ }
+ } else {
+- BlockPos blockpos = this.getBlockPosBelowThatAffectsMyMovement();
+- float f4 = this.level().getBlockState(blockpos).getBlock().getFriction();
++ BlockPos blockposition = this.getBlockPosBelowThatAffectsMyMovement();
++ float f4 = this.level().getBlockState(blockposition).getBlock().getFriction();
+
+ f = this.onGround() ? f4 * 0.91F : 0.91F;
+- Vec3 vec36 = this.handleRelativeFrictionAndCalculateMovement(vec3, f4);
+- double d8 = vec36.y;
++ Vec3 vec3d6 = this.handleRelativeFrictionAndCalculateMovement(travelVector, f4);
++ double d8 = vec3d6.y;
+
+ if (this.hasEffect(MobEffects.LEVITATION)) {
+- d8 += (0.05D * (double) (this.getEffect(MobEffects.LEVITATION).getAmplifier() + 1) - vec36.y) * 0.2D;
+- } else if (this.level().isClientSide && !this.level().hasChunkAt(blockpos)) {
++ d8 += (0.05D * (double) (this.getEffect(MobEffects.LEVITATION).getAmplifier() + 1) - vec3d6.y) * 0.2D;
++ } else if (this.level().isClientSide && !this.level().hasChunkAt(blockposition)) {
+ if (this.getY() > (double) this.level().getMinBuildHeight()) {
+ d8 = -0.1D;
+ } else {
+@@ -2314,23 +2738,23 @@
+ }
+
+ if (this.shouldDiscardFriction()) {
+- this.setDeltaMovement(vec36.x, d8, vec36.z);
++ this.setDeltaMovement(vec3d6.x, d8, vec3d6.z);
+ } else {
+- this.setDeltaMovement(vec36.x * (double) f, d8 * 0.9800000190734863D, vec36.z * (double) f);
++ this.setDeltaMovement(vec3d6.x * (double) f, d8 * 0.9800000190734863D, vec3d6.z * (double) f);
+ }
+ }
+ }
+
+- this.calculateEntityAnimation(this instanceof FlyingAnimal);
++ this.calculateEntityAnimation(this instanceof EntityBird);
+ }
+
+- private void travelRidden(Player player, Vec3 vec3) {
+- Vec3 vec31 = this.getRiddenInput(player, vec3);
++ private void travelRidden(net.minecraft.world.entity.player.Player player, Vec3 travelVector) {
++ Vec3 vec3d1 = this.getRiddenInput(player, travelVector);
+
+- this.tickRidden(player, vec31);
++ this.tickRidden(player, vec3d1);
+ if (this.isControlledByLocalInstance()) {
+ this.setSpeed(this.getRiddenSpeed(player));
+- this.travel(vec31);
++ this.travel(vec3d1);
+ } else {
+ this.calculateEntityAnimation(false);
+ this.setDeltaMovement(Vec3.ZERO);
+@@ -2339,98 +2763,97 @@
+
+ }
+
+- protected void tickRidden(Player player, Vec3 vec3) {}
++ protected void tickRidden(net.minecraft.world.entity.player.Player player, Vec3 travelVector) {}
+
+- protected Vec3 getRiddenInput(Player player, Vec3 vec3) {
+- return vec3;
++ protected Vec3 getRiddenInput(net.minecraft.world.entity.player.Player player, Vec3 travelVector) {
++ return travelVector;
+ }
+
+- protected float getRiddenSpeed(Player player) {
++ protected float getRiddenSpeed(net.minecraft.world.entity.player.Player player) {
+ return this.getSpeed();
+ }
+
+- public void calculateEntityAnimation(boolean flag) {
+- float f = (float) Mth.length(this.getX() - this.xo, flag ? this.getY() - this.yo : 0.0D, this.getZ() - this.zo);
++ public void calculateEntityAnimation(boolean includeHeight) {
++ float f = (float) Mth.length(this.getX() - this.xo, includeHeight ? this.getY() - this.yo : 0.0D, this.getZ() - this.zo);
+
+ this.updateWalkAnimation(f);
+ }
+
+- protected void updateWalkAnimation(float f) {
+- float f1 = Math.min(f * 4.0F, 1.0F);
++ protected void updateWalkAnimation(float partialTick) {
++ float f1 = Math.min(partialTick * 4.0F, 1.0F);
+
+ this.walkAnimation.update(f1, 0.4F);
+ }
+
+- public Vec3 handleRelativeFrictionAndCalculateMovement(Vec3 vec3, float f) {
+- this.moveRelative(this.getFrictionInfluencedSpeed(f), vec3);
++ public Vec3 handleRelativeFrictionAndCalculateMovement(Vec3 deltaMovement, float friction) {
++ this.moveRelative(this.getFrictionInfluencedSpeed(friction), deltaMovement);
+ this.setDeltaMovement(this.handleOnClimbable(this.getDeltaMovement()));
+- this.move(MoverType.SELF, this.getDeltaMovement());
+- Vec3 vec31 = this.getDeltaMovement();
++ this.move(EnumMoveType.SELF, this.getDeltaMovement());
++ Vec3 vec3d1 = this.getDeltaMovement();
+
+ if ((this.horizontalCollision || this.jumping) && (this.onClimbable() || this.getFeetBlockState().is(Blocks.POWDER_SNOW) && PowderSnowBlock.canEntityWalkOnPowderSnow(this))) {
+- vec31 = new Vec3(vec31.x, 0.2D, vec31.z);
++ vec3d1 = new Vec3(vec3d1.x, 0.2D, vec3d1.z);
+ }
+
+- return vec31;
++ return vec3d1;
+ }
+
+- public Vec3 getFluidFallingAdjustedMovement(double d0, boolean flag, Vec3 vec3) {
++ public Vec3 getFluidFallingAdjustedMovement(double gravity, boolean flag, Vec3 isFalling) {
+ if (!this.isNoGravity() && !this.isSprinting()) {
+ double d1;
+
+- if (flag && Math.abs(vec3.y - 0.005D) >= 0.003D && Math.abs(vec3.y - d0 / 16.0D) < 0.003D) {
++ if (flag && Math.abs(isFalling.y - 0.005D) >= 0.003D && Math.abs(isFalling.y - gravity / 16.0D) < 0.003D) {
+ d1 = -0.003D;
+ } else {
+- d1 = vec3.y - d0 / 16.0D;
++ d1 = isFalling.y - gravity / 16.0D;
+ }
+
+- return new Vec3(vec3.x, d1, vec3.z);
++ return new Vec3(isFalling.x, d1, isFalling.z);
+ } else {
+- return vec3;
++ return isFalling;
+ }
+ }
+
+- private Vec3 handleOnClimbable(Vec3 vec3) {
++ private Vec3 handleOnClimbable(Vec3 deltaMovement) {
+ if (this.onClimbable()) {
+ this.resetFallDistance();
+ float f = 0.15F;
+- double d0 = Mth.clamp(vec3.x, -0.15000000596046448D, 0.15000000596046448D);
+- double d1 = Mth.clamp(vec3.z, -0.15000000596046448D, 0.15000000596046448D);
+- double d2 = Math.max(vec3.y, -0.15000000596046448D);
++ double d0 = Mth.clamp(deltaMovement.x, -0.15000000596046448D, 0.15000000596046448D);
++ double d1 = Mth.clamp(deltaMovement.z, -0.15000000596046448D, 0.15000000596046448D);
++ double d2 = Math.max(deltaMovement.y, -0.15000000596046448D);
+
+- if (d2 < 0.0D && !this.getFeetBlockState().is(Blocks.SCAFFOLDING) && this.isSuppressingSlidingDownLadder() && this instanceof Player) {
++ if (d2 < 0.0D && !this.getFeetBlockState().is(Blocks.SCAFFOLDING) && this.isSuppressingSlidingDownLadder() && this instanceof net.minecraft.world.entity.player.Player) {
+ d2 = 0.0D;
+ }
+
+- vec3 = new Vec3(d0, d2, d1);
++ deltaMovement = new Vec3(d0, d2, d1);
+ }
+
+- return vec3;
++ return deltaMovement;
+ }
+
+- private float getFrictionInfluencedSpeed(float f) {
+- return this.onGround() ? this.getSpeed() * (0.21600002F / (f * f * f)) : this.getFlyingSpeed();
++ private float getFrictionInfluencedSpeed(float friction) {
++ return this.onGround() ? this.getSpeed() * (0.21600002F / (friction * friction * friction)) : this.getFlyingSpeed();
+ }
+
+ protected float getFlyingSpeed() {
+- return this.getControllingPassenger() instanceof Player ? this.getSpeed() * 0.1F : 0.02F;
++ return this.getControllingPassenger() instanceof net.minecraft.world.entity.player.Player ? this.getSpeed() * 0.1F : 0.02F;
+ }
+
+ public float getSpeed() {
+ return this.speed;
+ }
+
+- public void setSpeed(float f) {
+- this.speed = f;
++ public void setSpeed(float speed) {
++ this.speed = speed;
+ }
+
+- public boolean doHurtTarget(Entity entity) {
+- this.setLastHurtMob(entity);
++ public boolean doHurtTarget(Entity target) {
++ this.setLastHurtMob(target);
+ return false;
+ }
+
+ @Override
+- @Override
+ public void tick() {
+ super.tick();
+ this.updatingUsingItem();
+@@ -2462,7 +2885,7 @@
+ }
+ }
+
+- this.detectEquipmentUpdates();
++ this.detectEquipmentUpdatesPublic(); // CraftBukkit
+ if (this.tickCount % 20 == 0) {
+ this.getCombatTracker().recheckStatus();
+ }
+@@ -2559,7 +2982,7 @@
+ this.refreshDirtyAttributes();
+ }
+
+- private void detectEquipmentUpdates() {
++ public void detectEquipmentUpdatesPublic() { // CraftBukkit
+ Map<EquipmentSlot, ItemStack> map = this.collectEquipmentChanges();
+
+ if (map != null) {
+@@ -2574,38 +2997,38 @@
+ @Nullable
+ private Map<EquipmentSlot, ItemStack> collectEquipmentChanges() {
+ Map<EquipmentSlot, ItemStack> map = null;
+- EquipmentSlot[] aequipmentslot = EquipmentSlot.values();
+- int i = aequipmentslot.length;
++ EquipmentSlot[] aenumitemslot = EquipmentSlot.values();
++ int i = aenumitemslot.length;
+
+ for (int j = 0; j < i; ++j) {
+- EquipmentSlot equipmentslot = aequipmentslot[j];
++ EquipmentSlot enumitemslot = aenumitemslot[j];
+ ItemStack itemstack;
+
+- switch (equipmentslot.getType()) {
++ switch (enumitemslot.getType()) {
+ case HAND:
+- itemstack = this.getLastHandItem(equipmentslot);
++ itemstack = this.getLastHandItem(enumitemslot);
+ break;
+ case ARMOR:
+- itemstack = this.getLastArmorItem(equipmentslot);
++ itemstack = this.getLastArmorItem(enumitemslot);
+ break;
+ default:
+ continue;
+ }
+
+- ItemStack itemstack1 = this.getItemBySlot(equipmentslot);
++ ItemStack itemstack1 = this.getItemBySlot(enumitemslot);
+
+ if (this.equipmentHasChanged(itemstack, itemstack1)) {
+ if (map == null) {
+ map = Maps.newEnumMap(EquipmentSlot.class);
+ }
+
+- map.put(equipmentslot, itemstack1);
++ map.put(enumitemslot, itemstack1);
+ if (!itemstack.isEmpty()) {
+- this.getAttributes().removeAttributeModifiers(itemstack.getAttributeModifiers(equipmentslot));
++ this.getAttributes().removeAttributeModifiers(itemstack.getAttributeModifiers(enumitemslot));
+ }
+
+ if (!itemstack1.isEmpty()) {
+- this.getAttributes().addTransientAttributeModifiers(itemstack1.getAttributeModifiers(equipmentslot));
++ this.getAttributes().addTransientAttributeModifiers(itemstack1.getAttributeModifiers(enumitemslot));
+ }
+ }
+ }
+@@ -2613,61 +3036,61 @@
+ return map;
+ }
+
+- public boolean equipmentHasChanged(ItemStack itemstack, ItemStack itemstack1) {
+- return !ItemStack.matches(itemstack1, itemstack);
++ public boolean equipmentHasChanged(ItemStack oldItem, ItemStack newItem) {
++ return !ItemStack.matches(newItem, oldItem);
+ }
+
+- private void handleHandSwap(Map<EquipmentSlot, ItemStack> map) {
+- ItemStack itemstack = (ItemStack) map.get(EquipmentSlot.MAINHAND);
+- ItemStack itemstack1 = (ItemStack) map.get(EquipmentSlot.OFFHAND);
++ private void handleHandSwap(Map<EquipmentSlot, ItemStack> hands) {
++ ItemStack itemstack = (ItemStack) hands.get(EquipmentSlot.MAINHAND);
++ ItemStack itemstack1 = (ItemStack) hands.get(EquipmentSlot.OFFHAND);
+
+ if (itemstack != null && itemstack1 != null && ItemStack.matches(itemstack, this.getLastHandItem(EquipmentSlot.OFFHAND)) && ItemStack.matches(itemstack1, this.getLastHandItem(EquipmentSlot.MAINHAND))) {
+ ((ServerLevel) this.level()).getChunkSource().broadcast(this, new ClientboundEntityEventPacket(this, (byte) 55));
+- map.remove(EquipmentSlot.MAINHAND);
+- map.remove(EquipmentSlot.OFFHAND);
++ hands.remove(EquipmentSlot.MAINHAND);
++ hands.remove(EquipmentSlot.OFFHAND);
+ this.setLastHandItem(EquipmentSlot.MAINHAND, itemstack.copy());
+ this.setLastHandItem(EquipmentSlot.OFFHAND, itemstack1.copy());
+ }
+
+ }
+
+- private void handleEquipmentChanges(Map<EquipmentSlot, ItemStack> map) {
+- List<Pair<EquipmentSlot, ItemStack>> list = Lists.newArrayListWithCapacity(map.size());
++ private void handleEquipmentChanges(Map<EquipmentSlot, ItemStack> equipments) {
++ List<Pair<EquipmentSlot, ItemStack>> list = Lists.newArrayListWithCapacity(equipments.size());
+
+- map.forEach((equipmentslot, itemstack) -> {
++ equipments.forEach((enumitemslot, itemstack) -> {
+ ItemStack itemstack1 = itemstack.copy();
+
+- list.add(Pair.of(equipmentslot, itemstack1));
+- switch (equipmentslot.getType()) {
++ list.add(Pair.of(enumitemslot, itemstack1));
++ switch (enumitemslot.getType()) {
+ case HAND:
+- this.setLastHandItem(equipmentslot, itemstack1);
++ this.setLastHandItem(enumitemslot, itemstack1);
+ break;
+ case ARMOR:
+- this.setLastArmorItem(equipmentslot, itemstack1);
++ this.setLastArmorItem(enumitemslot, itemstack1);
+ }
+
+ });
+ ((ServerLevel) this.level()).getChunkSource().broadcast(this, new ClientboundSetEquipmentPacket(this.getId(), list));
+ }
+
+- private ItemStack getLastArmorItem(EquipmentSlot equipmentslot) {
+- return (ItemStack) this.lastArmorItemStacks.get(equipmentslot.getIndex());
++ private ItemStack getLastArmorItem(EquipmentSlot slot) {
++ return (ItemStack) this.lastArmorItemStacks.get(slot.getIndex());
+ }
+
+- private void setLastArmorItem(EquipmentSlot equipmentslot, ItemStack itemstack) {
+- this.lastArmorItemStacks.set(equipmentslot.getIndex(), itemstack);
++ private void setLastArmorItem(EquipmentSlot slot, ItemStack stack) {
++ this.lastArmorItemStacks.set(slot.getIndex(), stack);
+ }
+
+- private ItemStack getLastHandItem(EquipmentSlot equipmentslot) {
+- return (ItemStack) this.lastHandItemStacks.get(equipmentslot.getIndex());
++ private ItemStack getLastHandItem(EquipmentSlot slot) {
++ return (ItemStack) this.lastHandItemStacks.get(slot.getIndex());
+ }
+
+- private void setLastHandItem(EquipmentSlot equipmentslot, ItemStack itemstack) {
+- this.lastHandItemStacks.set(equipmentslot.getIndex(), itemstack);
++ private void setLastHandItem(EquipmentSlot slot, ItemStack stack) {
++ this.lastHandItemStacks.set(slot.getIndex(), stack);
+ }
+
+- protected float tickHeadTurn(float f, float f1) {
+- float f2 = Mth.wrapDegrees(f - this.yBodyRot);
++ protected float tickHeadTurn(float yRot, float animStep) {
++ float f2 = Mth.wrapDegrees(yRot - this.yBodyRot);
+
+ this.yBodyRot += f2 * 0.3F;
+ float f3 = Mth.wrapDegrees(this.getYRot() - this.yBodyRot);
+@@ -2680,10 +3103,10 @@
+ boolean flag = f3 < -90.0F || f3 >= 90.0F;
+
+ if (flag) {
+- f1 *= -1.0F;
++ animStep *= -1.0F;
+ }
+
+- return f1;
++ return animStep;
+ }
+
+ protected float getMaxHeadRotationRelativeToBody() {
+@@ -2712,20 +3135,20 @@
+ --this.lerpHeadSteps;
+ }
+
+- Vec3 vec3 = this.getDeltaMovement();
+- double d0 = vec3.x;
+- double d1 = vec3.y;
+- double d2 = vec3.z;
++ Vec3 vec3d = this.getDeltaMovement();
++ double d0 = vec3d.x;
++ double d1 = vec3d.y;
++ double d2 = vec3d.z;
+
+- if (Math.abs(vec3.x) < 0.003D) {
++ if (Math.abs(vec3d.x) < 0.003D) {
+ d0 = 0.0D;
+ }
+
+- if (Math.abs(vec3.y) < 0.003D) {
++ if (Math.abs(vec3d.y) < 0.003D) {
+ d1 = 0.0D;
+ }
+
+- if (Math.abs(vec3.z) < 0.003D) {
++ if (Math.abs(vec3d.z) < 0.003D) {
+ d2 = 0.0D;
+ }
+
+@@ -2772,8 +3195,8 @@
+ this.xxa *= 0.98F;
+ this.zza *= 0.98F;
+ this.updateFallFlying();
+- AABB aabb = this.getBoundingBox();
+- Vec3 vec31 = new Vec3((double) this.xxa, (double) this.yya, (double) this.zza);
++ AABB axisalignedbb = this.getBoundingBox();
++ Vec3 vec3d1 = new Vec3((double) this.xxa, (double) this.yya, (double) this.zza);
+
+ if (this.hasEffect(MobEffects.SLOW_FALLING) || this.hasEffect(MobEffects.LEVITATION)) {
+ this.resetFallDistance();
+@@ -2781,18 +3204,18 @@
+
+ label104:
+ {
+- LivingEntity livingentity = this.getControllingPassenger();
++ LivingEntity entityliving = this.getControllingPassenger();
+
+- if (livingentity instanceof Player) {
+- Player player = (Player) livingentity;
++ if (entityliving instanceof net.minecraft.world.entity.player.Player) {
++ net.minecraft.world.entity.player.Player entityhuman = (net.minecraft.world.entity.player.Player) entityliving;
+
+ if (this.isAlive()) {
+- this.travelRidden(player, vec31);
++ this.travelRidden(entityhuman, vec3d1);
+ break label104;
+ }
+ }
+
+- this.travel(vec31);
++ this.travel(vec3d1);
+ }
+
+ this.level().getProfiler().pop();
+@@ -2817,7 +3240,7 @@
+ this.level().getProfiler().push("push");
+ if (this.autoSpinAttackTicks > 0) {
+ --this.autoSpinAttackTicks;
+- this.checkAutoSpinAttack(aabb, this.getBoundingBox());
++ this.checkAutoSpinAttack(axisalignedbb, this.getBoundingBox());
+ }
+
+ this.pushEntities();
+@@ -2846,8 +3269,8 @@
+ int j = i / 10;
+
+ if (j % 2 == 0) {
+- itemstack.hurtAndBreak(1, this, (livingentity) -> {
+- livingentity.broadcastBreakEvent(EquipmentSlot.CHEST);
++ itemstack.hurtAndBreak(1, this, (entityliving) -> {
++ entityliving.broadcastBreakEvent(EquipmentSlot.CHEST);
+ });
+ }
+
+@@ -2861,6 +3284,7 @@
+ }
+
+ if (!this.level().isClientSide) {
++ if (flag != this.getSharedFlag(7) && !CraftEventFactory.callToggleGlideEvent(this, flag).isCancelled()) // CraftBukkit
+ this.setSharedFlag(7, flag);
+ }
+
+@@ -2870,7 +3294,7 @@
+
+ protected void pushEntities() {
+ if (this.level().isClientSide()) {
+- this.level().getEntities(EntityTypeTest.forClass(Player.class), this.getBoundingBox(), EntitySelector.pushableBy(this)).forEach(this::doPush);
++ this.level().getEntities(EntityTypeTest.forClass(net.minecraft.world.entity.player.Player.class), this.getBoundingBox(), EntitySelector.pushableBy(this)).forEach(this::doPush);
+ } else {
+ List<Entity> list = this.level().getEntities((Entity) this, this.getBoundingBox(), EntitySelector.pushableBy(this));
+
+@@ -2906,9 +3330,9 @@
+ }
+ }
+
+- protected void checkAutoSpinAttack(AABB aabb, AABB aabb1) {
+- AABB aabb2 = aabb.minmax(aabb1);
+- List<Entity> list = this.level().getEntities(this, aabb2);
++ protected void checkAutoSpinAttack(AABB boundingBoxBeforeSpin, AABB boundingBoxAfterSpin) {
++ AABB axisalignedbb2 = boundingBoxBeforeSpin.minmax(boundingBoxAfterSpin);
++ List<Entity> list = this.level().getEntities(this, axisalignedbb2);
+
+ if (!list.isEmpty()) {
+ Iterator iterator = list.iterator();
+@@ -2937,14 +3361,13 @@
+ entity.push(this);
+ }
+
+- protected void doAutoAttackOnTouch(LivingEntity livingentity) {}
++ protected void doAutoAttackOnTouch(LivingEntity target) {}
+
+ public boolean isAutoSpinAttack() {
+ return ((Byte) this.entityData.get(LivingEntity.DATA_LIVING_ENTITY_FLAGS) & 4) != 0;
+ }
+
+ @Override
+- @Override
+ public void stopRiding() {
+ Entity entity = this.getVehicle();
+
+@@ -2956,7 +3379,6 @@
+ }
+
+ @Override
+- @Override
+ public void rideTick() {
+ super.rideTick();
+ this.oRun = this.run;
+@@ -2965,7 +3387,6 @@
+ }
+
+ @Override
+- @Override
+ public void lerpTo(double d0, double d1, double d2, float f, float f1, int i) {
+ this.lerpX = d0;
+ this.lerpY = d1;
+@@ -2976,58 +3397,52 @@
+ }
+
+ @Override
+- @Override
+ public double lerpTargetX() {
+ return this.lerpSteps > 0 ? this.lerpX : this.getX();
+ }
+
+ @Override
+- @Override
+ public double lerpTargetY() {
+ return this.lerpSteps > 0 ? this.lerpY : this.getY();
+ }
+
+ @Override
+- @Override
+ public double lerpTargetZ() {
+ return this.lerpSteps > 0 ? this.lerpZ : this.getZ();
+ }
+
+ @Override
+- @Override
+ public float lerpTargetXRot() {
+ return this.lerpSteps > 0 ? (float) this.lerpXRot : this.getXRot();
+ }
+
+ @Override
+- @Override
+ public float lerpTargetYRot() {
+ return this.lerpSteps > 0 ? (float) this.lerpYRot : this.getYRot();
+ }
+
+ @Override
+- @Override
+- public void lerpHeadTo(float f, int i) {
+- this.lerpYHeadRot = (double) f;
+- this.lerpHeadSteps = i;
++ public void lerpHeadTo(float yaw, int pitch) {
++ this.lerpYHeadRot = (double) yaw;
++ this.lerpHeadSteps = pitch;
+ }
+
+- public void setJumping(boolean flag) {
+- this.jumping = flag;
++ public void setJumping(boolean jumping) {
++ this.jumping = jumping;
+ }
+
+- public void onItemPickup(ItemEntity itementity) {
+- Entity entity = itementity.getOwner();
++ public void onItemPickup(ItemEntity itemEntity) {
++ Entity entity = itemEntity.getOwner();
+
+ if (entity instanceof ServerPlayer) {
+- CriteriaTriggers.THROWN_ITEM_PICKED_UP_BY_ENTITY.trigger((ServerPlayer) entity, itementity.getItem(), this);
++ CriteriaTriggers.THROWN_ITEM_PICKED_UP_BY_ENTITY.trigger((ServerPlayer) entity, itemEntity.getItem(), this);
+ }
+
+ }
+
+- public void take(Entity entity, int i) {
++ public void take(Entity entity, int amount) {
+ if (!entity.isRemoved() && !this.level().isClientSide && (entity instanceof ItemEntity || entity instanceof AbstractArrow || entity instanceof ExperienceOrb)) {
+- ((ServerLevel) this.level()).getChunkSource().broadcast(entity, new ClientboundTakeItemEntityPacket(entity.getId(), this.getId(), i));
++ ((ServerLevel) this.level()).getChunkSource().broadcast(entity, new ClientboundTakeItemEntityPacket(entity.getId(), this.getId(), amount));
+ }
+
+ }
+@@ -3036,75 +3451,75 @@
+ if (entity.level() != this.level()) {
+ return false;
+ } else {
+- Vec3 vec3 = new Vec3(this.getX(), this.getEyeY(), this.getZ());
+- Vec3 vec31 = new Vec3(entity.getX(), entity.getEyeY(), entity.getZ());
++ Vec3 vec3d = new Vec3(this.getX(), this.getEyeY(), this.getZ());
++ Vec3 vec3d1 = new Vec3(entity.getX(), entity.getEyeY(), entity.getZ());
+
+- return vec31.distanceTo(vec3) > 128.0D ? false : this.level().clip(new ClipContext(vec3, vec31, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)).getType() == HitResult.Type.MISS;
++ return vec3d1.distanceTo(vec3d) > 128.0D ? false : this.level().clip(new ClipContext(vec3d, vec3d1, ClipContext.Block.COLLIDER, ClipContext.Fluid.NONE, this)).getType() == HitResult.EnumMovingObjectType.MISS;
+ }
+ }
+
+ @Override
+- @Override
+- public float getViewYRot(float f) {
+- return f == 1.0F ? this.yHeadRot : Mth.lerp(f, this.yHeadRotO, this.yHeadRot);
++ public float getViewYRot(float partialTicks) {
++ return partialTicks == 1.0F ? this.yHeadRot : Mth.lerp(partialTicks, this.yHeadRotO, this.yHeadRot);
+ }
+
+- public float getAttackAnim(float f) {
++ public float getAttackAnim(float partialTick) {
+ float f1 = this.attackAnim - this.oAttackAnim;
+
+ if (f1 < 0.0F) {
+ ++f1;
+ }
+
+- return this.oAttackAnim + f1 * f;
++ return this.oAttackAnim + f1 * partialTick;
+ }
+
+ @Override
+- @Override
+ public boolean isPickable() {
+- return !this.isRemoved();
++ return !this.isRemoved() && this.collides; // CraftBukkit
+ }
+
+ @Override
+- @Override
+ public boolean isPushable() {
+- return this.isAlive() && !this.isSpectator() && !this.onClimbable();
++ return this.isAlive() && !this.isSpectator() && !this.onClimbable() && this.collides; // CraftBukkit
+ }
+
++ // CraftBukkit start - collidable API
+ @Override
++ public boolean canCollideWithBukkit(Entity entity) {
++ return isPushable() && this.collides != this.collidableExemptions.contains(entity.getUUID());
++ }
++ // CraftBukkit end
++
+ @Override
+ public float getYHeadRot() {
+ return this.yHeadRot;
+ }
+
+ @Override
+- @Override
+- public void setYHeadRot(float f) {
+- this.yHeadRot = f;
++ public void setYHeadRot(float rotation) {
++ this.yHeadRot = rotation;
+ }
+
+ @Override
+- @Override
+- public void setYBodyRot(float f) {
+- this.yBodyRot = f;
++ public void setYBodyRot(float offset) {
++ this.yBodyRot = offset;
+ }
+
+ @Override
+- @Override
+- protected Vec3 getRelativePortalPosition(Direction.Axis direction_axis, BlockUtil.FoundRectangle blockutil_foundrectangle) {
+- return resetForwardDirectionOfRelativePortalPosition(super.getRelativePortalPosition(direction_axis, blockutil_foundrectangle));
++ protected Vec3 getRelativePortalPosition(Direction.Axis axis, BlockUtil.FoundRectangle portal) {
++ return resetForwardDirectionOfRelativePortalPosition(super.getRelativePortalPosition(axis, portal));
+ }
+
+- public static Vec3 resetForwardDirectionOfRelativePortalPosition(Vec3 vec3) {
+- return new Vec3(vec3.x, vec3.y, 0.0D);
++ public static Vec3 resetForwardDirectionOfRelativePortalPosition(Vec3 relativePortalPosition) {
++ return new Vec3(relativePortalPosition.x, relativePortalPosition.y, 0.0D);
+ }
+
+ public float getAbsorptionAmount() {
+ return this.absorptionAmount;
+ }
+
+- public final void setAbsorptionAmount(float f) {
+- this.internalSetAbsorptionAmount(Mth.clamp(f, 0.0F, this.getMaxAbsorption()));
++ public final void setAbsorptionAmount(float absorptionAmount) {
++ this.internalSetAbsorptionAmount(Mth.clamp(absorptionAmount, 0.0F, this.getMaxAbsorption()));
+ }
+
+ protected void internalSetAbsorptionAmount(float f) {
+@@ -3125,8 +3540,8 @@
+ return ((Byte) this.entityData.get(LivingEntity.DATA_LIVING_ENTITY_FLAGS) & 1) > 0;
+ }
+
+- public InteractionHand getUsedItemHand() {
+- return ((Byte) this.entityData.get(LivingEntity.DATA_LIVING_ENTITY_FLAGS) & 2) > 0 ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND;
++ public EnumHand getUsedItemHand() {
++ return ((Byte) this.entityData.get(LivingEntity.DATA_LIVING_ENTITY_FLAGS) & 2) > 0 ? EnumHand.OFF_HAND : EnumHand.MAIN_HAND;
+ }
+
+ private void updatingUsingItem() {
+@@ -3141,13 +3556,13 @@
+
+ }
+
+- protected void updateUsingItem(ItemStack itemstack) {
+- itemstack.onUseTick(this.level(), this, this.getUseItemRemainingTicks());
++ protected void updateUsingItem(ItemStack usingItem) {
++ usingItem.onUseTick(this.level(), this, this.getUseItemRemainingTicks());
+ if (this.shouldTriggerItemUseEffects()) {
+- this.triggerItemUseEffects(itemstack, 5);
++ this.triggerItemUseEffects(usingItem, 5);
+ }
+
+- if (--this.useItemRemaining == 0 && !this.level().isClientSide && !itemstack.useOnRelease()) {
++ if (--this.useItemRemaining == 0 && !this.level().isClientSide && !usingItem.useOnRelease()) {
+ this.completeUsingItem();
+ }
+
+@@ -3155,8 +3570,8 @@
+
+ private boolean shouldTriggerItemUseEffects() {
+ int i = this.getUseItemRemainingTicks();
+- FoodProperties foodproperties = this.useItem.getItem().getFoodProperties();
+- boolean flag = foodproperties != null && foodproperties.isFastFood();
++ FoodProperties foodinfo = this.useItem.getItem().getFoodProperties();
++ boolean flag = foodinfo != null && foodinfo.isFastFood();
+
+ flag |= i <= this.useItem.getUseDuration() - 7;
+ return flag && i % 4 == 0;
+@@ -3172,28 +3587,28 @@
+
+ }
+
+- protected void setLivingEntityFlag(int i, boolean flag) {
++ protected void setLivingEntityFlag(int key, boolean value) {
+ byte b0 = (Byte) this.entityData.get(LivingEntity.DATA_LIVING_ENTITY_FLAGS);
+ int j;
+
+- if (flag) {
+- j = b0 | i;
++ if (value) {
++ j = b0 | key;
+ } else {
+- j = b0 & ~i;
++ j = b0 & ~key;
+ }
+
+ this.entityData.set(LivingEntity.DATA_LIVING_ENTITY_FLAGS, (byte) j);
+ }
+
+- public void startUsingItem(InteractionHand interactionhand) {
+- ItemStack itemstack = this.getItemInHand(interactionhand);
++ public void startUsingItem(EnumHand hand) {
++ ItemStack itemstack = this.getItemInHand(hand);
+
+ if (!itemstack.isEmpty() && !this.isUsingItem()) {
+ this.useItem = itemstack;
+ this.useItemRemaining = itemstack.getUseDuration();
+ if (!this.level().isClientSide) {
+ this.setLivingEntityFlag(1, true);
+- this.setLivingEntityFlag(2, interactionhand == InteractionHand.OFF_HAND);
++ this.setLivingEntityFlag(2, hand == EnumHand.OFF_HAND);
+ this.gameEvent(GameEvent.ITEM_INTERACT_START);
+ }
+
+@@ -3201,14 +3616,13 @@
+ }
+
+ @Override
+- @Override
+- public void onSyncedDataUpdated(EntityDataAccessor<?> entitydataaccessor) {
+- super.onSyncedDataUpdated(entitydataaccessor);
+- if (LivingEntity.SLEEPING_POS_ID.equals(entitydataaccessor)) {
++ public void onSyncedDataUpdated(EntityDataAccessor<?> key) {
++ super.onSyncedDataUpdated(key);
++ if (LivingEntity.SLEEPING_POS_ID.equals(key)) {
+ if (this.level().isClientSide) {
+ this.getSleepingPos().ifPresent(this::setPosToBed);
+ }
+- } else if (LivingEntity.DATA_LIVING_ENTITY_FLAGS.equals(entitydataaccessor) && this.level().isClientSide) {
++ } else if (LivingEntity.DATA_LIVING_ENTITY_FLAGS.equals(key) && this.level().isClientSide) {
+ if (this.isUsingItem() && this.useItem.isEmpty()) {
+ this.useItem = this.getItemInHand(this.getUsedItemHand());
+ if (!this.useItem.isEmpty()) {
+@@ -3223,58 +3637,76 @@
+ }
+
+ @Override
+- @Override
+- public void lookAt(EntityAnchorArgument.Anchor entityanchorargument_anchor, Vec3 vec3) {
+- super.lookAt(entityanchorargument_anchor, vec3);
++ public void lookAt(EntityAnchorArgument.Anchor anchor, Vec3 target) {
++ super.lookAt(anchor, target);
+ this.yHeadRotO = this.yHeadRot;
+ this.yBodyRot = this.yHeadRot;
+ this.yBodyRotO = this.yBodyRot;
+ }
+
+- protected void triggerItemUseEffects(ItemStack itemstack, int i) {
+- if (!itemstack.isEmpty() && this.isUsingItem()) {
+- if (itemstack.getUseAnimation() == UseAnim.DRINK) {
+- this.playSound(this.getDrinkingSound(itemstack), 0.5F, this.level().random.nextFloat() * 0.1F + 0.9F);
++ protected void triggerItemUseEffects(ItemStack stack, int amount) {
++ if (!stack.isEmpty() && this.isUsingItem()) {
++ if (stack.getUseAnimation() == EnumAnimation.DRINK) {
++ this.playSound(this.getDrinkingSound(stack), 0.5F, this.level().random.nextFloat() * 0.1F + 0.9F);
+ }
+
+- if (itemstack.getUseAnimation() == UseAnim.EAT) {
+- this.spawnItemParticles(itemstack, i);
+- this.playSound(this.getEatingSound(itemstack), 0.5F + 0.5F * (float) this.random.nextInt(2), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F);
++ if (stack.getUseAnimation() == EnumAnimation.EAT) {
++ this.spawnItemParticles(stack, amount);
++ this.playSound(this.getEatingSound(stack), 0.5F + 0.5F * (float) this.random.nextInt(2), (this.random.nextFloat() - this.random.nextFloat()) * 0.2F + 1.0F);
+ }
+
+ }
+ }
+
+- private void spawnItemParticles(ItemStack itemstack, int i) {
+- for (int j = 0; j < i; ++j) {
+- Vec3 vec3 = new Vec3(((double) this.random.nextFloat() - 0.5D) * 0.1D, Math.random() * 0.1D + 0.1D, 0.0D);
++ private void spawnItemParticles(ItemStack stack, int amount) {
++ for (int j = 0; j < amount; ++j) {
++ Vec3 vec3d = new Vec3(((double) this.random.nextFloat() - 0.5D) * 0.1D, Math.random() * 0.1D + 0.1D, 0.0D);
+
+- vec3 = vec3.xRot(-this.getXRot() * 0.017453292F);
+- vec3 = vec3.yRot(-this.getYRot() * 0.017453292F);
++ vec3d = vec3d.xRot(-this.getXRot() * 0.017453292F);
++ vec3d = vec3d.yRot(-this.getYRot() * 0.017453292F);
+ double d0 = (double) (-this.random.nextFloat()) * 0.6D - 0.3D;
+- Vec3 vec31 = new Vec3(((double) this.random.nextFloat() - 0.5D) * 0.3D, d0, 0.6D);
++ Vec3 vec3d1 = new Vec3(((double) this.random.nextFloat() - 0.5D) * 0.3D, d0, 0.6D);
+
+- vec31 = vec31.xRot(-this.getXRot() * 0.017453292F);
+- vec31 = vec31.yRot(-this.getYRot() * 0.017453292F);
+- vec31 = vec31.add(this.getX(), this.getEyeY(), this.getZ());
+- this.level().addParticle(new ItemParticleOption(ParticleTypes.ITEM, itemstack), vec31.x, vec31.y, vec31.z, vec3.x, vec3.y + 0.05D, vec3.z);
++ vec3d1 = vec3d1.xRot(-this.getXRot() * 0.017453292F);
++ vec3d1 = vec3d1.yRot(-this.getYRot() * 0.017453292F);
++ vec3d1 = vec3d1.add(this.getX(), this.getEyeY(), this.getZ());
++ this.level().addParticle(new ItemParticleOption(ParticleTypes.ITEM, stack), vec3d1.x, vec3d1.y, vec3d1.z, vec3d.x, vec3d.y + 0.05D, vec3d.z);
+ }
+
+ }
+
+ protected void completeUsingItem() {
+ if (!this.level().isClientSide || this.isUsingItem()) {
+- InteractionHand interactionhand = this.getUsedItemHand();
++ EnumHand enumhand = this.getUsedItemHand();
+
+- if (!this.useItem.equals(this.getItemInHand(interactionhand))) {
++ if (!this.useItem.equals(this.getItemInHand(enumhand))) {
+ this.releaseUsingItem();
+ } else {
+ if (!this.useItem.isEmpty() && this.isUsingItem()) {
+ this.triggerItemUseEffects(this.useItem, 16);
+- ItemStack itemstack = this.useItem.finishUsingItem(this.level(), this);
++ // CraftBukkit start - fire PlayerItemConsumeEvent
++ ItemStack itemstack;
++ if (this instanceof ServerPlayer) {
++ org.bukkit.inventory.ItemStack craftItem = CraftItemStack.asBukkitCopy(this.useItem);
++ org.bukkit.inventory.EquipmentSlot hand = org.bukkit.craftbukkit.CraftEquipmentSlot.getHand(enumhand);
++ PlayerItemConsumeEvent event = new PlayerItemConsumeEvent((Player) this.getBukkitEntity(), craftItem, hand);
++ this.level().getCraftServer().getPluginManager().callEvent(event);
+
++ if (event.isCancelled()) {
++ // Update client
++ ((ServerPlayer) this).getBukkitEntity().updateInventory();
++ ((ServerPlayer) this).getBukkitEntity().updateScaledHealth();
++ return;
++ }
++
++ itemstack = (craftItem.equals(event.getItem())) ? this.useItem.finishUsingItem(this.level(), this) : CraftItemStack.asNMSCopy(event.getItem()).finishUsingItem(this.level(), this);
++ } else {
++ itemstack = this.useItem.finishUsingItem(this.level(), this);
++ }
++ // CraftBukkit end
++
+ if (itemstack != this.useItem) {
+- this.setItemInHand(interactionhand, itemstack);
++ this.setItemInHand(enumhand, itemstack);
+ }
+
+ this.stopUsingItem();
+@@ -3325,7 +3757,7 @@
+ if (this.isUsingItem() && !this.useItem.isEmpty()) {
+ Item item = this.useItem.getItem();
+
+- return item.getUseAnimation(this.useItem) != UseAnim.BLOCK ? false : item.getUseDuration(this.useItem) - this.useItemRemaining >= 5;
++ return item.getUseAnimation(this.useItem) != EnumAnimation.BLOCK ? false : item.getUseDuration(this.useItem) - this.useItemRemaining >= 5;
+ } else {
+ return false;
+ }
+@@ -3340,62 +3772,92 @@
+ }
+
+ @Override
+- @Override
+ public boolean isVisuallySwimming() {
+- return super.isVisuallySwimming() || !this.isFallFlying() && this.hasPose(Pose.FALL_FLYING);
++ return super.isVisuallySwimming() || !this.isFallFlying() && this.hasPose(EntityPose.FALL_FLYING);
+ }
+
+ public int getFallFlyingTicks() {
+ return this.fallFlyTicks;
+ }
+
+- public boolean randomTeleport(double d0, double d1, double d2, boolean flag) {
++ public boolean randomTeleport(double x, double d1, double y, boolean flag) {
++ // CraftBukkit start
++ return randomTeleport(x, d1, y, flag, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause.UNKNOWN).orElse(false);
++ }
++
++ public Optional<Boolean> randomTeleport(double d0, double d1, double d2, boolean flag, org.bukkit.event.player.PlayerTeleportEvent.TeleportCause cause) {
++ // CraftBukkit end
+ double d3 = this.getX();
+ double d4 = this.getY();
+ double d5 = this.getZ();
+ double d6 = d1;
+ boolean flag1 = false;
+- BlockPos blockpos = BlockPos.containing(d0, d1, d2);
+- Level level = this.level();
++ BlockPos blockposition = BlockPos.containing(d0, d1, d2);
++ Level world = this.level();
+
+- if (level.hasChunkAt(blockpos)) {
++ if (world.hasChunkAt(blockposition)) {
+ boolean flag2 = false;
+
+- while (!flag2 && blockpos.getY() > level.getMinBuildHeight()) {
+- BlockPos blockpos1 = blockpos.below();
+- BlockState blockstate = level.getBlockState(blockpos1);
++ while (!flag2 && blockposition.getY() > world.getMinBuildHeight()) {
++ BlockPos blockposition1 = blockposition.below();
++ IBlockData iblockdata = world.getBlockState(blockposition1);
+
+- if (blockstate.blocksMotion()) {
++ if (iblockdata.blocksMotion()) {
+ flag2 = true;
+ } else {
+ --d6;
+- blockpos = blockpos1;
++ blockposition = blockposition1;
+ }
+ }
+
+ if (flag2) {
+- this.teleportTo(d0, d6, d2);
+- if (level.noCollision((Entity) this) && !level.containsAnyLiquid(this.getBoundingBox())) {
++ // CraftBukkit start - Teleport event
++ // this.teleportTo(d0, d6, d2);
++
++ // first set position, to check if the place to teleport is valid
++ this.setPos(d0, d6, d2);
++ if (world.noCollision((Entity) this) && !world.containsAnyLiquid(this.getBoundingBox())) {
+ flag1 = true;
+ }
++ // now revert and call event if the teleport place is valid
++ this.setPos(d3, d4, d5);
++
++ if (flag1) {
++ if (!(this instanceof ServerPlayer)) {
++ EntityTeleportEvent teleport = new EntityTeleportEvent(this.getBukkitEntity(), new Location(this.level().getWorld(), d3, d4, d5), new Location(this.level().getWorld(), d0, d6, d2));
++ this.level().getCraftServer().getPluginManager().callEvent(teleport);
++ if (!teleport.isCancelled()) {
++ Location to = teleport.getTo();
++ this.teleportTo(to.getX(), to.getY(), to.getZ());
++ } else {
++ return Optional.empty();
++ }
++ } else {
++ // player teleport event is called in the underlining code
++ if (((ServerPlayer) this).connection.teleport(d0, d6, d2, this.getYRot(), this.getXRot(), java.util.Collections.emptySet(), cause)) {
++ return Optional.empty();
++ }
++ }
++ }
++ // CraftBukkit end
+ }
+ }
+
+ if (!flag1) {
+- this.teleportTo(d3, d4, d5);
+- return false;
++ // this.enderTeleportTo(d3, d4, d5); // CraftBukkit - already set the location back
++ return Optional.of(false); // CraftBukkit
+ } else {
+ if (flag) {
+- level.broadcastEntityEvent(this, (byte) 46);
++ world.broadcastEntityEvent(this, (byte) 46);
+ }
+
+ if (this instanceof PathfinderMob) {
+- PathfinderMob pathfindermob = (PathfinderMob) this;
++ PathfinderMob entitycreature = (PathfinderMob) this;
+
+- pathfindermob.getNavigation().stop();
++ entitycreature.getNavigation().stop();
+ }
+
+- return true;
++ return Optional.of(true); // CraftBukkit
+ }
+ }
+
+@@ -3407,36 +3869,34 @@
+ return true;
+ }
+
+- public void setRecordPlayingNearby(BlockPos blockpos, boolean flag) {}
++ public void setRecordPlayingNearby(BlockPos jukebox, boolean partyParrot) {}
+
+- public boolean canTakeItem(ItemStack itemstack) {
++ public boolean canTakeItem(ItemStack stack) {
+ return false;
+ }
+
+ @Override
+- @Override
+- public EntityDimensions getDimensions(Pose pose) {
+- return pose == Pose.SLEEPING ? LivingEntity.SLEEPING_DIMENSIONS : super.getDimensions(pose).scale(this.getScale());
++ public EntityDimensions getDimensions(EntityPose pose) {
++ return pose == EntityPose.SLEEPING ? LivingEntity.SLEEPING_DIMENSIONS : super.getDimensions(pose).scale(this.getScale());
+ }
+
+- public ImmutableList<Pose> getDismountPoses() {
+- return ImmutableList.of(Pose.STANDING);
++ public ImmutableList<EntityPose> getDismountPoses() {
++ return ImmutableList.of(EntityPose.STANDING);
+ }
+
+- public AABB getLocalBoundsForPose(Pose pose) {
+- EntityDimensions entitydimensions = this.getDimensions(pose);
++ public AABB getLocalBoundsForPose(EntityPose pose) {
++ EntityDimensions entitysize = this.getDimensions(pose);
+
+- return new AABB((double) (-entitydimensions.width / 2.0F), 0.0D, (double) (-entitydimensions.width / 2.0F), (double) (entitydimensions.width / 2.0F), (double) entitydimensions.height, (double) (entitydimensions.width / 2.0F));
++ return new AABB((double) (-entitysize.width / 2.0F), 0.0D, (double) (-entitysize.width / 2.0F), (double) (entitysize.width / 2.0F), (double) entitysize.height, (double) (entitysize.width / 2.0F));
+ }
+
+- protected boolean wouldNotSuffocateAtTargetPose(Pose pose) {
+- AABB aabb = this.getDimensions(pose).makeBoundingBox(this.position());
++ protected boolean wouldNotSuffocateAtTargetPose(EntityPose entitypose) {
++ AABB axisalignedbb = this.getDimensions(entitypose).makeBoundingBox(this.position());
+
+- return this.level().noBlockCollision(this, aabb);
++ return this.level().noBlockCollision(this, axisalignedbb);
+ }
+
+ @Override
+- @Override
+ public boolean canChangeDimensions() {
+ return super.canChangeDimensions() && !this.isSleeping();
+ }
+@@ -3445,8 +3905,8 @@
+ return (Optional) this.entityData.get(LivingEntity.SLEEPING_POS_ID);
+ }
+
+- public void setSleepingPos(BlockPos blockpos) {
+- this.entityData.set(LivingEntity.SLEEPING_POS_ID, Optional.of(blockpos));
++ public void setSleepingPos(BlockPos pos) {
++ this.entityData.set(LivingEntity.SLEEPING_POS_ID, Optional.of(pos));
+ }
+
+ public void clearSleepingPos() {
+@@ -3457,110 +3917,108 @@
+ return this.getSleepingPos().isPresent();
+ }
+
+- public void startSleeping(BlockPos blockpos) {
++ public void startSleeping(BlockPos pos) {
+ if (this.isPassenger()) {
+ this.stopRiding();
+ }
+
+- BlockState blockstate = this.level().getBlockState(blockpos);
++ IBlockData iblockdata = this.level().getBlockState(pos);
+
+- if (blockstate.getBlock() instanceof BedBlock) {
+- this.level().setBlock(blockpos, (BlockState) blockstate.setValue(BedBlock.OCCUPIED, true), 3);
++ if (iblockdata.getBlock() instanceof BedBlock) {
++ this.level().setBlock(pos, (IBlockData) iblockdata.setValue(BedBlock.OCCUPIED, true), 3);
+ }
+
+- this.setPose(Pose.SLEEPING);
+- this.setPosToBed(blockpos);
+- this.setSleepingPos(blockpos);
++ this.setPose(EntityPose.SLEEPING);
++ this.setPosToBed(pos);
++ this.setSleepingPos(pos);
+ this.setDeltaMovement(Vec3.ZERO);
+ this.hasImpulse = true;
+ }
+
+- private void setPosToBed(BlockPos blockpos) {
+- this.setPos((double) blockpos.getX() + 0.5D, (double) blockpos.getY() + 0.6875D, (double) blockpos.getZ() + 0.5D);
++ private void setPosToBed(BlockPos pos) {
++ this.setPos((double) pos.getX() + 0.5D, (double) pos.getY() + 0.6875D, (double) pos.getZ() + 0.5D);
+ }
+
+ private boolean checkBedExists() {
+- return (Boolean) this.getSleepingPos().map((blockpos) -> {
+- return this.level().getBlockState(blockpos).getBlock() instanceof BedBlock;
++ return (Boolean) this.getSleepingPos().map((blockposition) -> {
++ return this.level().getBlockState(blockposition).getBlock() instanceof BedBlock;
+ }).orElse(false);
+ }
+
+ public void stopSleeping() {
+- Optional optional = this.getSleepingPos();
+- Level level = this.level();
++ Optional<BlockPos> optional = this.getSleepingPos(); // CraftBukkit - decompile error
++ Level world = this.level();
+
+- java.util.Objects.requireNonNull(level);
+- optional.filter(level::hasChunkAt).ifPresent((blockpos) -> {
+- BlockState blockstate = this.level().getBlockState(blockpos);
++ java.util.Objects.requireNonNull(world);
++ optional.filter(world::hasChunkAt).ifPresent((blockposition) -> {
++ IBlockData iblockdata = this.level().getBlockState(blockposition);
+
+- if (blockstate.getBlock() instanceof BedBlock) {
+- Direction direction = (Direction) blockstate.getValue(BedBlock.FACING);
++ if (iblockdata.getBlock() instanceof BedBlock) {
++ Direction enumdirection = (Direction) iblockdata.getValue(BedBlock.FACING);
+
+- this.level().setBlock(blockpos, (BlockState) blockstate.setValue(BedBlock.OCCUPIED, false), 3);
+- Vec3 vec3 = (Vec3) BedBlock.findStandUpPosition(this.getType(), this.level(), blockpos, direction, this.getYRot()).orElseGet(() -> {
+- BlockPos blockpos1 = blockpos.above();
++ this.level().setBlock(blockposition, (IBlockData) iblockdata.setValue(BedBlock.OCCUPIED, false), 3);
++ Vec3 vec3d = (Vec3) BedBlock.findStandUpPosition(this.getType(), this.level(), blockposition, enumdirection, this.getYRot()).orElseGet(() -> {
++ BlockPos blockposition1 = blockposition.above();
+
+- return new Vec3((double) blockpos1.getX() + 0.5D, (double) blockpos1.getY() + 0.1D, (double) blockpos1.getZ() + 0.5D);
++ return new Vec3((double) blockposition1.getX() + 0.5D, (double) blockposition1.getY() + 0.1D, (double) blockposition1.getZ() + 0.5D);
+ });
+- Vec3 vec31 = Vec3.atBottomCenterOf(blockpos).subtract(vec3).normalize();
+- float f = (float) Mth.wrapDegrees(Mth.atan2(vec31.z, vec31.x) * 57.2957763671875D - 90.0D);
++ Vec3 vec3d1 = Vec3.atBottomCenterOf(blockposition).subtract(vec3d).normalize();
++ float f = (float) Mth.wrapDegrees(Mth.atan2(vec3d1.z, vec3d1.x) * 57.2957763671875D - 90.0D);
+
+- this.setPos(vec3.x, vec3.y, vec3.z);
++ this.setPos(vec3d.x, vec3d.y, vec3d.z);
+ this.setYRot(f);
+ this.setXRot(0.0F);
+ }
+
+ });
+- Vec3 vec3 = this.position();
++ Vec3 vec3d = this.position();
+
+- this.setPose(Pose.STANDING);
+- this.setPos(vec3.x, vec3.y, vec3.z);
++ this.setPose(EntityPose.STANDING);
++ this.setPos(vec3d.x, vec3d.y, vec3d.z);
+ this.clearSleepingPos();
+ }
+
+ @Nullable
+ public Direction getBedOrientation() {
+- BlockPos blockpos = (BlockPos) this.getSleepingPos().orElse((Object) null);
++ BlockPos blockposition = (BlockPos) this.getSleepingPos().orElse(null); // CraftBukkit - decompile error
+
+- return blockpos != null ? BedBlock.getBedOrientation(this.level(), blockpos) : null;
++ return blockposition != null ? BedBlock.getBedOrientation(this.level(), blockposition) : null;
+ }
+
+ @Override
+- @Override
+ public boolean isInWall() {
+ return !this.isSleeping() && super.isInWall();
+ }
+
+ @Override
+- @Override
+- protected final float getEyeHeight(Pose pose, EntityDimensions entitydimensions) {
+- return pose == Pose.SLEEPING ? 0.2F : this.getStandingEyeHeight(pose, entitydimensions);
++ protected final float getEyeHeight(EntityPose pose, EntityDimensions size) {
++ return pose == EntityPose.SLEEPING ? 0.2F : this.getStandingEyeHeight(pose, size);
+ }
+
+- protected float getStandingEyeHeight(Pose pose, EntityDimensions entitydimensions) {
+- return super.getEyeHeight(pose, entitydimensions);
++ protected float getStandingEyeHeight(EntityPose pose, EntityDimensions dimensions) {
++ return super.getEyeHeight(pose, dimensions);
+ }
+
+- public ItemStack getProjectile(ItemStack itemstack) {
++ public ItemStack getProjectile(ItemStack weaponStack) {
+ return ItemStack.EMPTY;
+ }
+
+- public ItemStack eat(Level level, ItemStack itemstack) {
+- if (itemstack.isEdible()) {
+- level.playSound((Player) null, this.getX(), this.getY(), this.getZ(), this.getEatingSound(itemstack), SoundSource.NEUTRAL, 1.0F, 1.0F + (level.random.nextFloat() - level.random.nextFloat()) * 0.4F);
+- this.addEatEffect(itemstack, level, this);
+- if (!(this instanceof Player) || !((Player) this).getAbilities().instabuild) {
+- itemstack.shrink(1);
++ public ItemStack eat(Level level, ItemStack food) {
++ if (food.isEdible()) {
++ level.playSound((net.minecraft.world.entity.player.Player) null, this.getX(), this.getY(), this.getZ(), this.getEatingSound(food), SoundSource.NEUTRAL, 1.0F, 1.0F + (level.random.nextFloat() - level.random.nextFloat()) * 0.4F);
++ this.addEatEffect(food, level, this);
++ if (!(this instanceof net.minecraft.world.entity.player.Player) || !((net.minecraft.world.entity.player.Player) this).getAbilities().instabuild) {
++ food.shrink(1);
+ }
+
+ this.gameEvent(GameEvent.EAT);
+ }
+
+- return itemstack;
++ return food;
+ }
+
+- private void addEatEffect(ItemStack itemstack, Level level, LivingEntity livingentity) {
+- Item item = itemstack.getItem();
++ private void addEatEffect(ItemStack food, Level level, LivingEntity livingEntity) {
++ Item item = food.getItem();
+
+ if (item.isEdible()) {
+ List<Pair<MobEffectInstance, Float>> list = item.getFoodProperties().getEffects();
+@@ -3570,15 +4028,15 @@
+ Pair<MobEffectInstance, Float> pair = (Pair) iterator.next();
+
+ if (!level.isClientSide && pair.getFirst() != null && level.random.nextFloat() < (Float) pair.getSecond()) {
+- livingentity.addEffect(new MobEffectInstance((MobEffectInstance) pair.getFirst()));
++ livingEntity.addEffect(new MobEffectInstance((MobEffectInstance) pair.getFirst()), EntityPotionEffectEvent.Cause.FOOD); // CraftBukkit
+ }
+ }
+ }
+
+ }
+
+- private static byte entityEventForEquipmentBreak(EquipmentSlot equipmentslot) {
+- switch (equipmentslot) {
++ private static byte entityEventForEquipmentBreak(EquipmentSlot slot) {
++ switch (slot) {
+ case MAINHAND:
+ return 47;
+ case OFFHAND:
+@@ -3596,16 +4054,15 @@
+ }
+ }
+
+- public void broadcastBreakEvent(EquipmentSlot equipmentslot) {
+- this.level().broadcastEntityEvent(this, entityEventForEquipmentBreak(equipmentslot));
++ public void broadcastBreakEvent(EquipmentSlot slot) {
++ this.level().broadcastEntityEvent(this, entityEventForEquipmentBreak(slot));
+ }
+
+- public void broadcastBreakEvent(InteractionHand interactionhand) {
+- this.broadcastBreakEvent(interactionhand == InteractionHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND);
++ public void broadcastBreakEvent(EnumHand hand) {
++ this.broadcastBreakEvent(hand == EnumHand.MAIN_HAND ? EquipmentSlot.MAINHAND : EquipmentSlot.OFFHAND);
+ }
+
+ @Override
+- @Override
+ public AABB getBoundingBoxForCulling() {
+ if (this.getItemBySlot(EquipmentSlot.HEAD).is(Items.DRAGON_HEAD)) {
+ float f = 0.5F;
+@@ -3616,33 +4073,31 @@
+ }
+ }
+
+- public static EquipmentSlot getEquipmentSlotForItem(ItemStack itemstack) {
+- Equipable equipable = Equipable.get(itemstack);
++ public static EquipmentSlot getEquipmentSlotForItem(ItemStack item) {
++ Equipable equipable = Equipable.get(item);
+
+ return equipable != null ? equipable.getEquipmentSlot() : EquipmentSlot.MAINHAND;
+ }
+
+- private static SlotAccess createEquipmentSlotAccess(LivingEntity livingentity, EquipmentSlot equipmentslot) {
+- return equipmentslot != EquipmentSlot.HEAD && equipmentslot != EquipmentSlot.MAINHAND && equipmentslot != EquipmentSlot.OFFHAND ? SlotAccess.forEquipmentSlot(livingentity, equipmentslot, (itemstack) -> {
+- return itemstack.isEmpty() || Mob.getEquipmentSlotForItem(itemstack) == equipmentslot;
+- }) : SlotAccess.forEquipmentSlot(livingentity, equipmentslot);
++ private static SlotAccess createEquipmentSlotAccess(LivingEntity entity, EquipmentSlot slot) {
++ return slot != EquipmentSlot.HEAD && slot != EquipmentSlot.MAINHAND && slot != EquipmentSlot.OFFHAND ? SlotAccess.forEquipmentSlot(entity, slot, (itemstack) -> {
++ return itemstack.isEmpty() || Mob.getEquipmentSlotForItem(itemstack) == slot;
++ }) : SlotAccess.forEquipmentSlot(entity, slot);
+ }
+
+ @Nullable
+- private static EquipmentSlot getEquipmentSlot(int i) {
+- return i == 100 + EquipmentSlot.HEAD.getIndex() ? EquipmentSlot.HEAD : (i == 100 + EquipmentSlot.CHEST.getIndex() ? EquipmentSlot.CHEST : (i == 100 + EquipmentSlot.LEGS.getIndex() ? EquipmentSlot.LEGS : (i == 100 + EquipmentSlot.FEET.getIndex() ? EquipmentSlot.FEET : (i == 98 ? EquipmentSlot.MAINHAND : (i == 99 ? EquipmentSlot.OFFHAND : null)))));
++ private static EquipmentSlot getEquipmentSlot(int index) {
++ return index == 100 + EquipmentSlot.HEAD.getIndex() ? EquipmentSlot.HEAD : (index == 100 + EquipmentSlot.CHEST.getIndex() ? EquipmentSlot.CHEST : (index == 100 + EquipmentSlot.LEGS.getIndex() ? EquipmentSlot.LEGS : (index == 100 + EquipmentSlot.FEET.getIndex() ? EquipmentSlot.FEET : (index == 98 ? EquipmentSlot.MAINHAND : (index == 99 ? EquipmentSlot.OFFHAND : null)))));
+ }
+
+ @Override
+- @Override
+- public SlotAccess getSlot(int i) {
+- EquipmentSlot equipmentslot = getEquipmentSlot(i);
++ public SlotAccess getSlot(int slot) {
++ EquipmentSlot enumitemslot = getEquipmentSlot(slot);
+
+- return equipmentslot != null ? createEquipmentSlotAccess(this, equipmentslot) : super.getSlot(i);
++ return enumitemslot != null ? createEquipmentSlotAccess(this, enumitemslot) : super.getSlot(slot);
+ }
+
+ @Override
+- @Override
+ public boolean canFreeze() {
+ if (this.isSpectator()) {
+ return false;
+@@ -3654,35 +4109,32 @@
+ }
+
+ @Override
+- @Override
+ public boolean isCurrentlyGlowing() {
+ return !this.level().isClientSide() && this.hasEffect(MobEffects.GLOWING) || super.isCurrentlyGlowing();
+ }
+
+ @Override
+- @Override
+ public float getVisualRotationYInDegrees() {
+ return this.yBodyRot;
+ }
+
+ @Override
+- @Override
+- public void recreateFromPacket(ClientboundAddEntityPacket clientboundaddentitypacket) {
+- double d0 = clientboundaddentitypacket.getX();
+- double d1 = clientboundaddentitypacket.getY();
+- double d2 = clientboundaddentitypacket.getZ();
+- float f = clientboundaddentitypacket.getYRot();
+- float f1 = clientboundaddentitypacket.getXRot();
++ public void recreateFromPacket(ClientboundAddEntityPacket packet) {
++ double d0 = packet.getX();
++ double d1 = packet.getY();
++ double d2 = packet.getZ();
++ float f = packet.getYRot();
++ float f1 = packet.getXRot();
+
+ this.syncPacketPositionCodec(d0, d1, d2);
+- this.yBodyRot = clientboundaddentitypacket.getYHeadRot();
+- this.yHeadRot = clientboundaddentitypacket.getYHeadRot();
++ this.yBodyRot = packet.getYHeadRot();
++ this.yHeadRot = packet.getYHeadRot();
+ this.yBodyRotO = this.yBodyRot;
+ this.yHeadRotO = this.yHeadRot;
+- this.setId(clientboundaddentitypacket.getId());
+- this.setUUID(clientboundaddentitypacket.getUUID());
++ this.setId(packet.getId());
++ this.setUUID(packet.getUUID());
+ this.absMoveTo(d0, d1, d2, f, f1);
+- this.setDeltaMovement(clientboundaddentitypacket.getXa(), clientboundaddentitypacket.getYa(), clientboundaddentitypacket.getZa());
++ this.setDeltaMovement(packet.getXa(), packet.getYa(), packet.getZa());
+ }
+
+ public boolean canDisableShield() {
+@@ -3690,21 +4142,18 @@
+ }
+
+ @Override
+- @Override
+ public float maxUpStep() {
+ float f = super.maxUpStep();
+
+- return this.getControllingPassenger() instanceof Player ? Math.max(f, 1.0F) : f;
++ return this.getControllingPassenger() instanceof net.minecraft.world.entity.player.Player ? Math.max(f, 1.0F) : f;
+ }
+
+ @Override
+- @Override
+ public Vec3 getPassengerRidingPosition(Entity entity) {
+ return (new Vec3(this.getPassengerAttachmentPoint(entity, this.getDimensions(this.getPose()), this.getScale()).rotateY(-this.yBodyRot * 0.017453292F))).add(this.position());
+ }
+
+ @Override
+- @Override
+ public float getMyRidingOffset(Entity entity) {
+ return this.ridingOffset(entity) * this.getScale();
+ }
+@@ -3713,7 +4162,7 @@
+ this.yHeadRot = (float) Mth.rotLerp(1.0D / (double) i, (double) this.yHeadRot, d0);
+ }
+
+- public static record Fallsounds(SoundEvent small, SoundEvent big) {
++ public static record a(SoundEvent small, SoundEvent big) {
+
+ }
+ }