diff options
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.patch | 4042 |
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) { + + } + } |