--- a/net/minecraft/world/entity/animal/Wolf.java
+++ b/net/minecraft/world/entity/animal/Wolf.java
@@ -70,13 +70,21 @@
 import net.minecraft.world.phys.Vec3;
 import org.joml.Vector3f;
 
+// CraftBukkit start
+import org.bukkit.event.entity.EntityRegainHealthEvent;
+import org.bukkit.event.entity.EntityTargetEvent;
+import org.bukkit.craftbukkit.v1_20_R2.event.CraftEventFactory;
+// CraftBukkit end
+
 public class Wolf extends TamableAnimal implements NeutralMob {
+
     private static final EntityDataAccessor<Boolean> DATA_INTERESTED_ID = SynchedEntityData.defineId(Wolf.class, EntityDataSerializers.BOOLEAN);
     private static final EntityDataAccessor<Integer> DATA_COLLAR_COLOR = SynchedEntityData.defineId(Wolf.class, EntityDataSerializers.INT);
     private static final EntityDataAccessor<Integer> DATA_REMAINING_ANGER_TIME = SynchedEntityData.defineId(Wolf.class, EntityDataSerializers.INT);
-    public static final Predicate<LivingEntity> PREY_SELECTOR = (entity) -> {
-        EntityType<?> entityType = entity.getType();
-        return entityType == EntityType.SHEEP || entityType == EntityType.RABBIT || entityType == EntityType.FOX;
+    public static final Predicate<LivingEntity> PREY_SELECTOR = (entityliving) -> {
+        EntityType<?> entitytypes = entityliving.getType();
+
+        return entitytypes == EntityType.SHEEP || entitytypes == EntityType.RABBIT || entitytypes == EntityType.FOX;
     };
     private static final float START_HEALTH = 8.0F;
     private static final float TAME_HEALTH = 20.0F;
@@ -113,24 +121,24 @@
         this.goalSelector.addGoal(10, new RandomLookAroundGoal(this));
         this.targetSelector.addGoal(1, new OwnerHurtByTargetGoal(this));
         this.targetSelector.addGoal(2, new OwnerHurtTargetGoal(this));
-        this.targetSelector.addGoal(3, (new HurtByTargetGoal(this)).setAlertOthers());
+        this.targetSelector.addGoal(3, (new HurtByTargetGoal(this, new Class[0])).setAlertOthers());
         this.targetSelector.addGoal(4, new NearestAttackableTargetGoal<>(this, Player.class, 10, true, false, this::isAngryAt));
-        this.targetSelector.addGoal(5, new NonTameRandomTargetGoal<>(this, Animal.class, false, PREY_SELECTOR));
+        this.targetSelector.addGoal(5, new NonTameRandomTargetGoal<>(this, Animal.class, false, Wolf.PREY_SELECTOR));
         this.targetSelector.addGoal(6, new NonTameRandomTargetGoal<>(this, Turtle.class, false, Turtle.BABY_ON_LAND_SELECTOR));
         this.targetSelector.addGoal(7, new NearestAttackableTargetGoal<>(this, AbstractSkeleton.class, false));
         this.targetSelector.addGoal(8, new ResetUniversalAngerTargetGoal<>(this, true));
     }
 
     public static AttributeSupplier.Builder createAttributes() {
-        return Mob.createMobAttributes().add(Attributes.MOVEMENT_SPEED, (double)0.3F).add(Attributes.MAX_HEALTH, 8.0D).add(Attributes.ATTACK_DAMAGE, 2.0D);
+        return Mob.createMobAttributes().add(Attributes.MOVEMENT_SPEED, 0.30000001192092896D).add(Attributes.MAX_HEALTH, 8.0D).add(Attributes.ATTACK_DAMAGE, 2.0D);
     }
 
     @Override
     protected void defineSynchedData() {
         super.defineSynchedData();
-        this.entityData.define(DATA_INTERESTED_ID, false);
-        this.entityData.define(DATA_COLLAR_COLOR, DyeColor.RED.getId());
-        this.entityData.define(DATA_REMAINING_ANGER_TIME, 0);
+        this.entityData.define(Wolf.DATA_INTERESTED_ID, false);
+        this.entityData.define(Wolf.DATA_COLLAR_COLOR, DyeColor.RED.getId());
+        this.entityData.define(Wolf.DATA_REMAINING_ANGER_TIME, 0);
     }
 
     @Override
@@ -141,7 +149,7 @@
     @Override
     public void addAdditionalSaveData(CompoundTag nbt) {
         super.addAdditionalSaveData(nbt);
-        nbt.putByte("CollarColor", (byte)this.getCollarColor().getId());
+        nbt.putByte("CollarColor", (byte) this.getCollarColor().getId());
         this.addPersistentAngerSaveData(nbt);
     }
 
@@ -157,13 +165,7 @@
 
     @Override
     protected SoundEvent getAmbientSound() {
-        if (this.isAngry()) {
-            return SoundEvents.WOLF_GROWL;
-        } else if (this.random.nextInt(3) == 0) {
-            return this.isTame() && this.getHealth() < 10.0F ? SoundEvents.WOLF_WHINE : SoundEvents.WOLF_PANT;
-        } else {
-            return SoundEvents.WOLF_AMBIENT;
-        }
+        return this.isAngry() ? SoundEvents.WOLF_GROWL : (this.random.nextInt(3) == 0 ? (this.isTame() && this.getHealth() < 10.0F ? SoundEvents.WOLF_WHINE : SoundEvents.WOLF_PANT) : SoundEvents.WOLF_AMBIENT);
     }
 
     @Override
@@ -188,11 +190,11 @@
             this.isShaking = true;
             this.shakeAnim = 0.0F;
             this.shakeAnimO = 0.0F;
-            this.level().broadcastEntityEvent(this, (byte)8);
+            this.level().broadcastEntityEvent(this, (byte) 8);
         }
 
         if (!this.level().isClientSide) {
-            this.updatePersistentAnger((ServerLevel)this.level(), true);
+            this.updatePersistentAnger((ServerLevel) this.level(), true);
         }
 
     }
@@ -211,7 +213,7 @@
             if (this.isInWaterRainOrBubble()) {
                 this.isWet = true;
                 if (this.isShaking && !this.level().isClientSide) {
-                    this.level().broadcastEntityEvent(this, (byte)56);
+                    this.level().broadcastEntityEvent(this, (byte) 56);
                     this.cancelShake();
                 }
             } else if ((this.isWet || this.isShaking) && this.isShaking) {
@@ -230,14 +232,15 @@
                 }
 
                 if (this.shakeAnim > 0.4F) {
-                    float f = (float)this.getY();
-                    int i = (int)(Mth.sin((this.shakeAnim - 0.4F) * (float)Math.PI) * 7.0F);
-                    Vec3 vec3 = this.getDeltaMovement();
+                    float f = (float) this.getY();
+                    int i = (int) (Mth.sin((this.shakeAnim - 0.4F) * 3.1415927F) * 7.0F);
+                    Vec3 vec3d = this.getDeltaMovement();
 
-                    for(int j = 0; j < i; ++j) {
-                        float g = (this.random.nextFloat() * 2.0F - 1.0F) * this.getBbWidth() * 0.5F;
-                        float h = (this.random.nextFloat() * 2.0F - 1.0F) * this.getBbWidth() * 0.5F;
-                        this.level().addParticle(ParticleTypes.SPLASH, this.getX() + (double)g, (double)(f + 0.8F), this.getZ() + (double)h, vec3.x, vec3.y, vec3.z);
+                    for (int j = 0; j < i; ++j) {
+                        float f1 = (this.random.nextFloat() * 2.0F - 1.0F) * this.getBbWidth() * 0.5F;
+                        float f2 = (this.random.nextFloat() * 2.0F - 1.0F) * this.getBbWidth() * 0.5F;
+
+                        this.level().addParticle(ParticleTypes.SPLASH, this.getX() + (double) f1, (double) (f + 0.8F), this.getZ() + (double) f2, vec3d.x, vec3d.y, vec3d.z);
                     }
                 }
             }
@@ -268,19 +271,20 @@
         return Math.min(0.5F + Mth.lerp(tickDelta, this.shakeAnimO, this.shakeAnim) / 2.0F * 0.5F, 1.0F);
     }
 
-    public float getBodyRollAngle(float tickDelta, float f) {
-        float g = (Mth.lerp(tickDelta, this.shakeAnimO, this.shakeAnim) + f) / 1.8F;
-        if (g < 0.0F) {
-            g = 0.0F;
-        } else if (g > 1.0F) {
-            g = 1.0F;
+    public float getBodyRollAngle(float tickDelta, float f1) {
+        float f2 = (Mth.lerp(tickDelta, this.shakeAnimO, this.shakeAnim) + f1) / 1.8F;
+
+        if (f2 < 0.0F) {
+            f2 = 0.0F;
+        } else if (f2 > 1.0F) {
+            f2 = 1.0F;
         }
 
-        return Mth.sin(g * (float)Math.PI) * Mth.sin(g * (float)Math.PI * 11.0F) * 0.15F * (float)Math.PI;
+        return Mth.sin(f2 * 3.1415927F) * Mth.sin(f2 * 3.1415927F * 11.0F) * 0.15F * 3.1415927F;
     }
 
     public float getHeadRollAngle(float tickDelta) {
-        return Mth.lerp(tickDelta, this.interestedAngleO, this.interestedAngle) * 0.15F * (float)Math.PI;
+        return Mth.lerp(tickDelta, this.interestedAngleO, this.interestedAngle) * 0.15F * 3.1415927F;
     }
 
     @Override
@@ -299,26 +303,32 @@
             return false;
         } else {
             Entity entity = source.getEntity();
-            if (!this.level().isClientSide) {
-                this.setOrderedToSit(false);
-            }
+
+            // CraftBukkit - move diff down
 
             if (entity != null && !(entity instanceof Player) && !(entity instanceof AbstractArrow)) {
                 amount = (amount + 1.0F) / 2.0F;
             }
 
-            return super.hurt(source, amount);
+            // CraftBukkit start
+            boolean result = super.hurt(source, amount);
+            if (!this.level().isClientSide && result) {
+                this.setOrderedToSit(false);
+            }
+            return result;
+            // CraftBukkit end
         }
     }
 
     @Override
     public boolean doHurtTarget(Entity target) {
-        boolean bl = target.hurt(this.damageSources().mobAttack(this), (float)((int)this.getAttributeValue(Attributes.ATTACK_DAMAGE)));
-        if (bl) {
+        boolean flag = target.hurt(this.damageSources().mobAttack(this), (float) ((int) this.getAttributeValue(Attributes.ATTACK_DAMAGE)));
+
+        if (flag) {
             this.doEnchantDamageEffects(this, target);
         }
 
-        return bl;
+        return flag;
     }
 
     @Override
@@ -326,7 +336,7 @@
         super.setTame(tamed);
         if (tamed) {
             this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(20.0D);
-            this.setHealth(20.0F);
+            this.setHealth(this.getMaxHealth()); // CraftBukkit - 20.0 -> getMaxHealth()
         } else {
             this.getAttribute(Attributes.MAX_HEALTH).setBaseValue(8.0D);
         }
@@ -336,28 +346,40 @@
 
     @Override
     public InteractionResult mobInteract(Player player, InteractionHand hand) {
-        ItemStack itemStack = player.getItemInHand(hand);
-        Item item = itemStack.getItem();
+        ItemStack itemstack = player.getItemInHand(hand);
+        Item item = itemstack.getItem();
+
         if (this.level().isClientSide) {
-            boolean bl = this.isOwnedBy(player) || this.isTame() || itemStack.is(Items.BONE) && !this.isTame() && !this.isAngry();
-            return bl ? InteractionResult.CONSUME : InteractionResult.PASS;
+            boolean flag = this.isOwnedBy(player) || this.isTame() || itemstack.is(Items.BONE) && !this.isTame() && !this.isAngry();
+
+            return flag ? InteractionResult.CONSUME : InteractionResult.PASS;
         } else if (this.isTame()) {
-            if (this.isFood(itemStack) && this.getHealth() < this.getMaxHealth()) {
+            if (this.isFood(itemstack) && this.getHealth() < this.getMaxHealth()) {
                 if (!player.getAbilities().instabuild) {
-                    itemStack.shrink(1);
+                    itemstack.shrink(1);
                 }
 
-                this.heal((float)item.getFoodProperties().getNutrition());
+                this.heal((float) item.getFoodProperties().getNutrition(), EntityRegainHealthEvent.RegainReason.EATING); // CraftBukkit
                 return InteractionResult.SUCCESS;
             } else {
                 if (item instanceof DyeItem) {
-                    DyeItem dyeItem = (DyeItem)item;
+                    DyeItem itemdye = (DyeItem) item;
+
                     if (this.isOwnedBy(player)) {
-                        DyeColor dyeColor = dyeItem.getDyeColor();
-                        if (dyeColor != this.getCollarColor()) {
-                            this.setCollarColor(dyeColor);
+                        DyeColor enumcolor = itemdye.getDyeColor();
+
+                        if (enumcolor != this.getCollarColor()) {
+                            // Paper start
+                            final io.papermc.paper.event.entity.EntityDyeEvent event = new io.papermc.paper.event.entity.EntityDyeEvent(this.getBukkitEntity(), org.bukkit.DyeColor.getByWoolData((byte) enumcolor.getId()), ((net.minecraft.server.level.ServerPlayer) player).getBukkitEntity());
+                            if (!event.callEvent()) {
+                                return InteractionResult.FAIL;
+                            }
+                            enumcolor = DyeColor.byId(event.getColor().getWoolData());
+                            // Paper end
+
+                            this.setCollarColor(enumcolor);
                             if (!player.getAbilities().instabuild) {
-                                itemStack.shrink(1);
+                                itemstack.shrink(1);
                             }
 
                             return InteractionResult.SUCCESS;
@@ -367,30 +389,32 @@
                     }
                 }
 
-                InteractionResult interactionResult = super.mobInteract(player, hand);
-                if ((!interactionResult.consumesAction() || this.isBaby()) && this.isOwnedBy(player)) {
+                InteractionResult enuminteractionresult = super.mobInteract(player, hand);
+
+                if ((!enuminteractionresult.consumesAction() || this.isBaby()) && this.isOwnedBy(player)) {
                     this.setOrderedToSit(!this.isOrderedToSit());
                     this.jumping = false;
                     this.navigation.stop();
-                    this.setTarget((LivingEntity)null);
+                    this.setTarget((LivingEntity) null, EntityTargetEvent.TargetReason.FORGOT_TARGET, true); // CraftBukkit - reason
                     return InteractionResult.SUCCESS;
                 } else {
-                    return interactionResult;
+                    return enuminteractionresult;
                 }
             }
-        } else if (itemStack.is(Items.BONE) && !this.isAngry()) {
+        } else if (itemstack.is(Items.BONE) && !this.isAngry()) {
             if (!player.getAbilities().instabuild) {
-                itemStack.shrink(1);
+                itemstack.shrink(1);
             }
 
-            if (this.random.nextInt(3) == 0) {
+            // CraftBukkit - added event call and isCancelled check.
+            if (this.random.nextInt(3) == 0 && !CraftEventFactory.callEntityTameEvent(this, player).isCancelled()) {
                 this.tame(player);
                 this.navigation.stop();
-                this.setTarget((LivingEntity)null);
+                this.setTarget((LivingEntity) null);
                 this.setOrderedToSit(true);
-                this.level().broadcastEntityEvent(this, (byte)7);
+                this.level().broadcastEntityEvent(this, (byte) 7);
             } else {
-                this.level().broadcastEntityEvent(this, (byte)6);
+                this.level().broadcastEntityEvent(this, (byte) 6);
             }
 
             return InteractionResult.SUCCESS;
@@ -414,16 +438,13 @@
     }
 
     public float getTailAngle() {
-        if (this.isAngry()) {
-            return 1.5393804F;
-        } else {
-            return this.isTame() ? (0.55F - (this.getMaxHealth() - this.getHealth()) * 0.02F) * (float)Math.PI : ((float)Math.PI / 5F);
-        }
+        return this.isAngry() ? 1.5393804F : (this.isTame() ? (0.55F - (this.getMaxHealth() - this.getHealth()) * 0.02F) * 3.1415927F : 0.62831855F);
     }
 
     @Override
     public boolean isFood(ItemStack stack) {
         Item item = stack.getItem();
+
         return item.isEdible() && item.getFoodProperties().isMeat();
     }
 
@@ -434,17 +455,17 @@
 
     @Override
     public int getRemainingPersistentAngerTime() {
-        return this.entityData.get(DATA_REMAINING_ANGER_TIME);
+        return (Integer) this.entityData.get(Wolf.DATA_REMAINING_ANGER_TIME);
     }
 
     @Override
     public void setRemainingPersistentAngerTime(int angerTime) {
-        this.entityData.set(DATA_REMAINING_ANGER_TIME, angerTime);
+        this.entityData.set(Wolf.DATA_REMAINING_ANGER_TIME, angerTime);
     }
 
     @Override
     public void startPersistentAngerTimer() {
-        this.setRemainingPersistentAngerTime(PERSISTENT_ANGER_TIME.sample(this.random));
+        this.setRemainingPersistentAngerTime(Wolf.PERSISTENT_ANGER_TIME.sample(this.random));
     }
 
     @Nullable
@@ -459,30 +480,32 @@
     }
 
     public DyeColor getCollarColor() {
-        return DyeColor.byId(this.entityData.get(DATA_COLLAR_COLOR));
+        return DyeColor.byId((Integer) this.entityData.get(Wolf.DATA_COLLAR_COLOR));
     }
 
     public void setCollarColor(DyeColor color) {
-        this.entityData.set(DATA_COLLAR_COLOR, color.getId());
+        this.entityData.set(Wolf.DATA_COLLAR_COLOR, color.getId());
     }
 
     @Nullable
     @Override
-    public Wolf getBreedOffspring(ServerLevel serverLevel, AgeableMob ageableMob) {
-        Wolf wolf = EntityType.WOLF.create(serverLevel);
-        if (wolf != null) {
-            UUID uUID = this.getOwnerUUID();
-            if (uUID != null) {
-                wolf.setOwnerUUID(uUID);
-                wolf.setTame(true);
+    public Wolf getBreedOffspring(ServerLevel world, AgeableMob entity) {
+        Wolf entitywolf = (Wolf) EntityType.WOLF.create(world);
+
+        if (entitywolf != null) {
+            UUID uuid = this.getOwnerUUID();
+
+            if (uuid != null) {
+                entitywolf.setOwnerUUID(uuid);
+                entitywolf.setTame(true);
             }
         }
 
-        return wolf;
+        return entitywolf;
     }
 
     public void setIsInterested(boolean begging) {
-        this.entityData.set(DATA_INTERESTED_ID, begging);
+        this.entityData.set(Wolf.DATA_INTERESTED_ID, begging);
     }
 
     @Override
@@ -494,33 +517,25 @@
         } else if (!(other instanceof Wolf)) {
             return false;
         } else {
-            Wolf wolf = (Wolf)other;
-            if (!wolf.isTame()) {
-                return false;
-            } else if (wolf.isInSittingPose()) {
-                return false;
-            } else {
-                return this.isInLove() && wolf.isInLove();
-            }
+            Wolf entitywolf = (Wolf) other;
+
+            return !entitywolf.isTame() ? false : (entitywolf.isInSittingPose() ? false : this.isInLove() && entitywolf.isInLove());
         }
     }
 
     public boolean isInterested() {
-        return this.entityData.get(DATA_INTERESTED_ID);
+        return (Boolean) this.entityData.get(Wolf.DATA_INTERESTED_ID);
     }
 
     @Override
     public boolean wantsToAttack(LivingEntity target, LivingEntity owner) {
         if (!(target instanceof Creeper) && !(target instanceof Ghast)) {
             if (target instanceof Wolf) {
-                Wolf wolf = (Wolf)target;
-                return !wolf.isTame() || wolf.getOwner() != owner;
-            } else if (target instanceof Player && owner instanceof Player && !((Player)owner).canHarmPlayer((Player)target)) {
-                return false;
-            } else if (target instanceof AbstractHorse && ((AbstractHorse)target).isTamed()) {
-                return false;
+                Wolf entitywolf = (Wolf) target;
+
+                return !entitywolf.isTame() || entitywolf.getOwner() != owner;
             } else {
-                return !(target instanceof TamableAnimal) || !((TamableAnimal)target).isTame();
+                return target instanceof Player && owner instanceof Player && !((Player) owner).canHarmPlayer((Player) target) ? false : (target instanceof AbstractHorse && ((AbstractHorse) target).isTamed() ? false : !(target instanceof TamableAnimal) || !((TamableAnimal) target).isTame());
             }
         } else {
             return false;
@@ -534,7 +549,7 @@
 
     @Override
     public Vec3 getLeashOffset() {
-        return new Vec3(0.0D, (double)(0.6F * this.getEyeHeight()), (double)(this.getBbWidth() * 0.4F));
+        return new Vec3(0.0D, (double) (0.6F * this.getEyeHeight()), (double) (this.getBbWidth() * 0.4F));
     }
 
     @Override
@@ -546,21 +561,30 @@
         return world.getBlockState(pos.below()).is(BlockTags.WOLVES_SPAWNABLE_ON) && isBrightEnoughToSpawn(world, pos);
     }
 
-    class WolfAvoidEntityGoal<T extends LivingEntity> extends AvoidEntityGoal<T> {
+    private class WolfPanicGoal extends PanicGoal {
+
+        public WolfPanicGoal(double d0) {
+            super(Wolf.this, d0);
+        }
+
+        @Override
+        protected boolean shouldPanic() {
+            return this.mob.isFreezing() || this.mob.isOnFire();
+        }
+    }
+
+    private class WolfAvoidEntityGoal<T extends LivingEntity> extends AvoidEntityGoal<T> {
+
         private final Wolf wolf;
 
-        public WolfAvoidEntityGoal(Wolf wolf, Class<T> fleeFromType, float distance, double slowSpeed, double fastSpeed) {
-            super(wolf, fleeFromType, distance, slowSpeed, fastSpeed);
-            this.wolf = wolf;
+        public WolfAvoidEntityGoal(Wolf entitywolf, Class oclass, float f, double d0, double d1) {
+            super(entitywolf, oclass, f, d0, d1);
+            this.wolf = entitywolf;
         }
 
         @Override
         public boolean canUse() {
-            if (super.canUse() && this.toAvoid instanceof Llama) {
-                return !this.wolf.isTame() && this.avoidLlama((Llama)this.toAvoid);
-            } else {
-                return false;
-            }
+            return super.canUse() && this.toAvoid instanceof Llama ? !this.wolf.isTame() && this.avoidLlama((Llama) this.toAvoid) : false;
         }
 
         private boolean avoidLlama(Llama llama) {
@@ -569,25 +593,14 @@
 
         @Override
         public void start() {
-            Wolf.this.setTarget((LivingEntity)null);
+            Wolf.this.setTarget((LivingEntity) null);
             super.start();
         }
 
         @Override
         public void tick() {
-            Wolf.this.setTarget((LivingEntity)null);
+            Wolf.this.setTarget((LivingEntity) null);
             super.tick();
         }
     }
-
-    class WolfPanicGoal extends PanicGoal {
-        public WolfPanicGoal(double speed) {
-            super(Wolf.this, speed);
-        }
-
-        @Override
-        protected boolean shouldPanic() {
-            return this.mob.isFreezing() || this.mob.isOnFire();
-        }
-    }
 }
