--- a/net/minecraft/world/entity/animal/Fox.java
+++ b/net/minecraft/world/entity/animal/Fox.java
@@ -2,6 +2,7 @@
 
 import com.google.common.collect.Lists;
 import java.util.EnumSet;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Optional;
 import java.util.UUID;
@@ -91,8 +92,12 @@
 import net.minecraft.world.level.gameevent.GameEvent;
 import net.minecraft.world.level.pathfinder.PathType;
 import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.event.entity.EntityRemoveEvent;
+// CraftBukkit end
 
 public class Fox extends Animal implements VariantHolder<Fox.Type> {
+
     private static final EntityDataAccessor<Integer> DATA_TYPE_ID = SynchedEntityData.defineId(Fox.class, EntityDataSerializers.INT);
     private static final EntityDataAccessor<Byte> DATA_FLAGS_ID = SynchedEntityData.defineId(Fox.class, EntityDataSerializers.BYTE);
     private static final int FLAG_SITTING = 1;
@@ -104,12 +109,22 @@
     private static final int FLAG_DEFENDING = 128;
     public static final EntityDataAccessor<Optional<UUID>> DATA_TRUSTED_ID_0 = SynchedEntityData.defineId(Fox.class, EntityDataSerializers.OPTIONAL_UUID);
     public static final EntityDataAccessor<Optional<UUID>> DATA_TRUSTED_ID_1 = SynchedEntityData.defineId(Fox.class, EntityDataSerializers.OPTIONAL_UUID);
-    static final Predicate<ItemEntity> ALLOWED_ITEMS = item -> !item.hasPickUpDelay() && item.isAlive();
-    private static final Predicate<Entity> TRUSTED_TARGET_SELECTOR = entity -> entity instanceof LivingEntity livingEntity
-            && livingEntity.getLastHurtMob() != null
-            && livingEntity.getLastHurtMobTimestamp() < livingEntity.tickCount + 600;
-    static final Predicate<Entity> STALKABLE_PREY = entity -> entity instanceof Chicken || entity instanceof Rabbit;
-    private static final Predicate<Entity> AVOID_PLAYERS = entity -> !entity.isDiscrete() && EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(entity);
+    static final Predicate<ItemEntity> ALLOWED_ITEMS = (entityitem) -> {
+        return !entityitem.hasPickUpDelay() && entityitem.isAlive();
+    };
+    private static final Predicate<Entity> TRUSTED_TARGET_SELECTOR = (entity) -> {
+        if (!(entity instanceof LivingEntity entityliving)) {
+            return false;
+        } else {
+            return entityliving.getLastHurtMob() != null && entityliving.getLastHurtMobTimestamp() < entityliving.tickCount + 600;
+        }
+    };
+    static final Predicate<Entity> STALKABLE_PREY = (entity) -> {
+        return entity instanceof Chicken || entity instanceof Rabbit;
+    };
+    private static final Predicate<Entity> AVOID_PLAYERS = (entity) -> {
+        return !entity.isDiscrete() && EntitySelector.NO_CREATIVE_OR_SPECTATOR.test(entity);
+    };
     private static final int MIN_TICKS_BEFORE_EAT = 600;
     private static final EntityDimensions BABY_DIMENSIONS = EntityType.FOX.getDimensions().scale(0.5F).withEyeHeight(0.2975F);
     private Goal landTargetGoal;
@@ -133,53 +148,51 @@
     @Override
     protected void defineSynchedData(SynchedEntityData.Builder builder) {
         super.defineSynchedData(builder);
-        builder.define(DATA_TRUSTED_ID_0, Optional.empty());
-        builder.define(DATA_TRUSTED_ID_1, Optional.empty());
-        builder.define(DATA_TYPE_ID, 0);
-        builder.define(DATA_FLAGS_ID, (byte)0);
+        builder.define(Fox.DATA_TRUSTED_ID_0, Optional.empty());
+        builder.define(Fox.DATA_TRUSTED_ID_1, Optional.empty());
+        builder.define(Fox.DATA_TYPE_ID, 0);
+        builder.define(Fox.DATA_FLAGS_ID, (byte) 0);
     }
 
     @Override
     protected void registerGoals() {
-        this.landTargetGoal = new NearestAttackableTargetGoal<>(
-            this, Animal.class, 10, false, false, entity -> entity instanceof Chicken || entity instanceof Rabbit
-        );
+        this.landTargetGoal = new NearestAttackableTargetGoal<>(this, Animal.class, 10, false, false, (entityliving) -> {
+            return entityliving instanceof Chicken || entityliving instanceof Rabbit;
+        });
         this.turtleEggTargetGoal = new NearestAttackableTargetGoal<>(this, Turtle.class, 10, false, false, Turtle.BABY_ON_LAND_SELECTOR);
-        this.fishTargetGoal = new NearestAttackableTargetGoal<>(this, AbstractFish.class, 20, false, false, entity -> entity instanceof AbstractSchoolingFish);
+        this.fishTargetGoal = new NearestAttackableTargetGoal<>(this, AbstractFish.class, 20, false, false, (entityliving) -> {
+            return entityliving instanceof AbstractSchoolingFish;
+        });
         this.goalSelector.addGoal(0, new Fox.FoxFloatGoal());
         this.goalSelector.addGoal(0, new ClimbOnTopOfPowderSnowGoal(this, this.level()));
         this.goalSelector.addGoal(1, new Fox.FaceplantGoal());
-        this.goalSelector.addGoal(2, new Fox.FoxPanicGoal(2.2));
-        this.goalSelector.addGoal(3, new Fox.FoxBreedGoal(1.0));
-        this.goalSelector
-            .addGoal(
-                4,
-                new AvoidEntityGoal<>(
-                    this, Player.class, 16.0F, 1.6, 1.4, entity -> AVOID_PLAYERS.test(entity) && !this.trusts(entity.getUUID()) && !this.isDefending()
-                )
-            );
-        this.goalSelector.addGoal(4, new AvoidEntityGoal<>(this, Wolf.class, 8.0F, 1.6, 1.4, entity -> !((Wolf)entity).isTame() && !this.isDefending()));
-        this.goalSelector.addGoal(4, new AvoidEntityGoal<>(this, PolarBear.class, 8.0F, 1.6, 1.4, entity -> !this.isDefending()));
+        this.goalSelector.addGoal(2, new Fox.FoxPanicGoal(2.2D));
+        this.goalSelector.addGoal(3, new Fox.FoxBreedGoal(this, 1.0D));
+        this.goalSelector.addGoal(4, new AvoidEntityGoal<>(this, Player.class, 16.0F, 1.6D, 1.4D, (entityliving) -> {
+            return Fox.AVOID_PLAYERS.test(entityliving) && !this.trusts(entityliving.getUUID()) && !this.isDefending();
+        }));
+        this.goalSelector.addGoal(4, new AvoidEntityGoal<>(this, Wolf.class, 8.0F, 1.6D, 1.4D, (entityliving) -> {
+            return !((Wolf) entityliving).isTame() && !this.isDefending();
+        }));
+        this.goalSelector.addGoal(4, new AvoidEntityGoal<>(this, PolarBear.class, 8.0F, 1.6D, 1.4D, (entityliving) -> {
+            return !this.isDefending();
+        }));
         this.goalSelector.addGoal(5, new Fox.StalkPreyGoal());
         this.goalSelector.addGoal(6, new Fox.FoxPounceGoal());
-        this.goalSelector.addGoal(6, new Fox.SeekShelterGoal(1.25));
-        this.goalSelector.addGoal(7, new Fox.FoxMeleeAttackGoal(1.2F, true));
+        this.goalSelector.addGoal(6, new Fox.SeekShelterGoal(1.25D));
+        this.goalSelector.addGoal(7, new Fox.FoxMeleeAttackGoal(1.2000000476837158D, true));
         this.goalSelector.addGoal(7, new Fox.SleepGoal());
-        this.goalSelector.addGoal(8, new Fox.FoxFollowParentGoal(this, 1.25));
+        this.goalSelector.addGoal(8, new Fox.FoxFollowParentGoal(this, this, 1.25D));
         this.goalSelector.addGoal(9, new Fox.FoxStrollThroughVillageGoal(32, 200));
-        this.goalSelector.addGoal(10, new Fox.FoxEatBerriesGoal(1.2F, 12, 1));
+        this.goalSelector.addGoal(10, new Fox.FoxEatBerriesGoal(1.2000000476837158D, 12, 1));
         this.goalSelector.addGoal(10, new LeapAtTargetGoal(this, 0.4F));
-        this.goalSelector.addGoal(11, new WaterAvoidingRandomStrollGoal(this, 1.0));
+        this.goalSelector.addGoal(11, new WaterAvoidingRandomStrollGoal(this, 1.0D));
         this.goalSelector.addGoal(11, new Fox.FoxSearchForItemsGoal());
         this.goalSelector.addGoal(12, new Fox.FoxLookAtPlayerGoal(this, Player.class, 24.0F));
         this.goalSelector.addGoal(13, new Fox.PerchAndSearchGoal());
-        this.targetSelector
-            .addGoal(
-                3,
-                new Fox.DefendTrustedTargetGoal(
-                    LivingEntity.class, false, false, entity -> TRUSTED_TARGET_SELECTOR.test(entity) && !this.trusts(entity.getUUID())
-                )
-            );
+        this.targetSelector.addGoal(3, new Fox.DefendTrustedTargetGoal(LivingEntity.class, false, false, (entityliving) -> {
+            return Fox.TRUSTED_TARGET_SELECTOR.test(entityliving) && !this.trusts(entityliving.getUUID());
+        }));
     }
 
     @Override
@@ -190,24 +203,27 @@
     @Override
     public void aiStep() {
         if (!this.level().isClientSide && this.isAlive() && this.isEffectiveAi()) {
-            this.ticksSinceEaten++;
-            ItemStack itemStack = this.getItemBySlot(EquipmentSlot.MAINHAND);
-            if (this.canEat(itemStack)) {
+            ++this.ticksSinceEaten;
+            ItemStack itemstack = this.getItemBySlot(EquipmentSlot.MAINHAND);
+
+            if (this.canEat(itemstack)) {
                 if (this.ticksSinceEaten > 600) {
-                    ItemStack itemStack2 = itemStack.finishUsingItem(this.level(), this);
-                    if (!itemStack2.isEmpty()) {
-                        this.setItemSlot(EquipmentSlot.MAINHAND, itemStack2);
+                    ItemStack itemstack1 = itemstack.finishUsingItem(this.level(), this);
+
+                    if (!itemstack1.isEmpty()) {
+                        this.setItemSlot(EquipmentSlot.MAINHAND, itemstack1);
                     }
 
                     this.ticksSinceEaten = 0;
                 } else if (this.ticksSinceEaten > 560 && this.random.nextFloat() < 0.1F) {
-                    this.playSound(this.getEatingSound(itemStack), 1.0F, 1.0F);
-                    this.level().broadcastEntityEvent(this, (byte)45);
+                    this.playSound(this.getEatingSound(itemstack), 1.0F, 1.0F);
+                    this.level().broadcastEntityEvent(this, (byte) 45);
                 }
             }
 
-            LivingEntity livingEntity = this.getTarget();
-            if (livingEntity == null || !livingEntity.isAlive()) {
+            LivingEntity entityliving = this.getTarget();
+
+            if (entityliving == null || !entityliving.isAlive()) {
                 this.setIsCrouching(false);
                 this.setIsInterested(false);
             }
@@ -223,6 +239,7 @@
         if (this.isDefending() && this.random.nextFloat() < 0.05F) {
             this.playSound(SoundEvents.FOX_AGGRO, 1.0F, 1.0F);
         }
+
     }
 
     @Override
@@ -238,69 +255,59 @@
     protected void populateDefaultEquipmentSlots(RandomSource random, DifficultyInstance localDifficulty) {
         if (random.nextFloat() < 0.2F) {
             float f = random.nextFloat();
-            ItemStack itemStack;
+            ItemStack itemstack;
+
             if (f < 0.05F) {
-                itemStack = new ItemStack(Items.EMERALD);
+                itemstack = new ItemStack(Items.EMERALD);
             } else if (f < 0.2F) {
-                itemStack = new ItemStack(Items.EGG);
+                itemstack = new ItemStack(Items.EGG);
             } else if (f < 0.4F) {
-                itemStack = random.nextBoolean() ? new ItemStack(Items.RABBIT_FOOT) : new ItemStack(Items.RABBIT_HIDE);
+                itemstack = random.nextBoolean() ? new ItemStack(Items.RABBIT_FOOT) : new ItemStack(Items.RABBIT_HIDE);
             } else if (f < 0.6F) {
-                itemStack = new ItemStack(Items.WHEAT);
+                itemstack = new ItemStack(Items.WHEAT);
             } else if (f < 0.8F) {
-                itemStack = new ItemStack(Items.LEATHER);
+                itemstack = new ItemStack(Items.LEATHER);
             } else {
-                itemStack = new ItemStack(Items.FEATHER);
+                itemstack = new ItemStack(Items.FEATHER);
             }
 
-            this.setItemSlot(EquipmentSlot.MAINHAND, itemStack);
+            this.setItemSlot(EquipmentSlot.MAINHAND, itemstack);
         }
+
     }
 
     @Override
     public void handleEntityEvent(byte status) {
         if (status == 45) {
-            ItemStack itemStack = this.getItemBySlot(EquipmentSlot.MAINHAND);
-            if (!itemStack.isEmpty()) {
-                for (int i = 0; i < 8; i++) {
-                    Vec3 vec3 = new Vec3(((double)this.random.nextFloat() - 0.5) * 0.1, Math.random() * 0.1 + 0.1, 0.0)
-                        .xRot(-this.getXRot() * (float) (Math.PI / 180.0))
-                        .yRot(-this.getYRot() * (float) (Math.PI / 180.0));
-                    this.level()
-                        .addParticle(
-                            new ItemParticleOption(ParticleTypes.ITEM, itemStack),
-                            this.getX() + this.getLookAngle().x / 2.0,
-                            this.getY(),
-                            this.getZ() + this.getLookAngle().z / 2.0,
-                            vec3.x,
-                            vec3.y + 0.05,
-                            vec3.z
-                        );
+            ItemStack itemstack = this.getItemBySlot(EquipmentSlot.MAINHAND);
+
+            if (!itemstack.isEmpty()) {
+                for (int i = 0; i < 8; ++i) {
+                    Vec3 vec3d = (new Vec3(((double) this.random.nextFloat() - 0.5D) * 0.1D, Math.random() * 0.1D + 0.1D, 0.0D)).xRot(-this.getXRot() * 0.017453292F).yRot(-this.getYRot() * 0.017453292F);
+
+                    this.level().addParticle(new ItemParticleOption(ParticleTypes.ITEM, itemstack), this.getX() + this.getLookAngle().x / 2.0D, this.getY(), this.getZ() + this.getLookAngle().z / 2.0D, vec3d.x, vec3d.y + 0.05D, vec3d.z);
                 }
             }
         } else {
             super.handleEntityEvent(status);
         }
+
     }
 
     public static AttributeSupplier.Builder createAttributes() {
-        return Mob.createMobAttributes()
-            .add(Attributes.MOVEMENT_SPEED, 0.3F)
-            .add(Attributes.MAX_HEALTH, 10.0)
-            .add(Attributes.FOLLOW_RANGE, 32.0)
-            .add(Attributes.ATTACK_DAMAGE, 2.0)
-            .add(Attributes.SAFE_FALL_DISTANCE, 5.0);
+        return Mob.createMobAttributes().add(Attributes.MOVEMENT_SPEED, 0.30000001192092896D).add(Attributes.MAX_HEALTH, 10.0D).add(Attributes.FOLLOW_RANGE, 32.0D).add(Attributes.ATTACK_DAMAGE, 2.0D).add(Attributes.SAFE_FALL_DISTANCE, 5.0D);
     }
 
     @Nullable
     @Override
-    public Fox getBreedOffspring(ServerLevel serverLevel, AgeableMob ageableMob) {
-        Fox fox = EntityType.FOX.create(serverLevel);
-        if (fox != null) {
-            fox.setVariant(this.random.nextBoolean() ? this.getVariant() : ((Fox)ageableMob).getVariant());
+    public Fox getBreedOffspring(ServerLevel world, AgeableMob entity) {
+        Fox entityfox = (Fox) EntityType.FOX.create(world);
+
+        if (entityfox != null) {
+            entityfox.setVariant(this.random.nextBoolean() ? this.getVariant() : ((Fox) entity).getVariant());
         }
 
-        return fox;
+        return entityfox;
     }
 
     public static boolean checkFoxSpawnRules(EntityType<Fox> type, LevelAccessor world, MobSpawnType spawnReason, BlockPos pos, RandomSource random) {
@@ -311,19 +318,20 @@
     @Override
     public SpawnGroupData finalizeSpawn(ServerLevelAccessor world, DifficultyInstance difficulty, MobSpawnType spawnReason, @Nullable SpawnGroupData entityData) {
         Holder<Biome> holder = world.getBiome(this.blockPosition());
-        Fox.Type type = Fox.Type.byBiome(holder);
-        boolean bl = false;
-        if (entityData instanceof Fox.FoxGroupData foxGroupData) {
-            type = foxGroupData.type;
-            if (foxGroupData.getGroupSize() >= 2) {
-                bl = true;
+        Fox.Type entityfox_type = Fox.Type.byBiome(holder);
+        boolean flag = false;
+
+        if (entityData instanceof Fox.FoxGroupData entityfox_i) {
+            entityfox_type = entityfox_i.type;
+            if (entityfox_i.getGroupSize() >= 2) {
+                flag = true;
             }
         } else {
-            entityData = new Fox.FoxGroupData(type);
+            entityData = new Fox.FoxGroupData(entityfox_type);
         }
 
-        this.setVariant(type);
-        if (bl) {
+        this.setVariant(entityfox_type);
+        if (flag) {
             this.setAge(-24000);
         }
 
@@ -332,7 +340,7 @@
         }
 
         this.populateDefaultEquipmentSlots(world.getRandom(), difficulty);
-        return super.finalizeSpawn(world, difficulty, spawnReason, entityData);
+        return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData);
     }
 
     private void setTargetGoals() {
@@ -345,6 +353,7 @@
             this.targetSelector.addGoal(6, this.landTargetGoal);
             this.targetSelector.addGoal(6, this.turtleEggTargetGoal);
         }
+
     }
 
     @Override
@@ -358,47 +367,51 @@
 
     @Override
     public EntityDimensions getDefaultDimensions(Pose pose) {
-        return this.isBaby() ? BABY_DIMENSIONS : super.getDefaultDimensions(pose);
+        return this.isBaby() ? Fox.BABY_DIMENSIONS : super.getDefaultDimensions(pose);
     }
 
     @Override
     public Fox.Type getVariant() {
-        return Fox.Type.byId(this.entityData.get(DATA_TYPE_ID));
+        return Fox.Type.byId((Integer) this.entityData.get(Fox.DATA_TYPE_ID));
     }
 
-    @Override
     public void setVariant(Fox.Type variant) {
-        this.entityData.set(DATA_TYPE_ID, variant.getId());
+        this.entityData.set(Fox.DATA_TYPE_ID, variant.getId());
     }
 
     List<UUID> getTrustedUUIDs() {
         List<UUID> list = Lists.newArrayList();
-        list.add(this.entityData.get(DATA_TRUSTED_ID_0).orElse(null));
-        list.add(this.entityData.get(DATA_TRUSTED_ID_1).orElse(null));
+
+        list.add((UUID) ((Optional) this.entityData.get(Fox.DATA_TRUSTED_ID_0)).orElse((Object) null));
+        list.add((UUID) ((Optional) this.entityData.get(Fox.DATA_TRUSTED_ID_1)).orElse((Object) null));
         return list;
     }
 
     void addTrustedUUID(@Nullable UUID uuid) {
-        if (this.entityData.get(DATA_TRUSTED_ID_0).isPresent()) {
-            this.entityData.set(DATA_TRUSTED_ID_1, Optional.ofNullable(uuid));
+        if (((Optional) this.entityData.get(Fox.DATA_TRUSTED_ID_0)).isPresent()) {
+            this.entityData.set(Fox.DATA_TRUSTED_ID_1, Optional.ofNullable(uuid));
         } else {
-            this.entityData.set(DATA_TRUSTED_ID_0, Optional.ofNullable(uuid));
+            this.entityData.set(Fox.DATA_TRUSTED_ID_0, Optional.ofNullable(uuid));
         }
+
     }
 
     @Override
     public void addAdditionalSaveData(CompoundTag nbt) {
         super.addAdditionalSaveData(nbt);
         List<UUID> list = this.getTrustedUUIDs();
-        ListTag listTag = new ListTag();
+        ListTag nbttaglist = new ListTag();
+        Iterator iterator = list.iterator();
 
-        for (UUID uUID : list) {
-            if (uUID != null) {
-                listTag.add(NbtUtils.createUUID(uUID));
+        while (iterator.hasNext()) {
+            UUID uuid = (UUID) iterator.next();
+
+            if (uuid != null) {
+                nbttaglist.add(NbtUtils.createUUID(uuid));
             }
         }
 
-        nbt.put("Trusted", listTag);
+        nbt.put("Trusted", nbttaglist);
         nbt.putBoolean("Sleeping", this.isSleeping());
         nbt.putString("Type", this.getVariant().getSerializedName());
         nbt.putBoolean("Sitting", this.isSitting());
@@ -408,18 +421,23 @@
     @Override
     public void readAdditionalSaveData(CompoundTag nbt) {
         super.readAdditionalSaveData(nbt);
+        ListTag nbttaglist = nbt.getList("Trusted", 11);
+        Iterator iterator = nbttaglist.iterator();
 
-        for (Tag tag : nbt.getList("Trusted", 11)) {
-            this.addTrustedUUID(NbtUtils.loadUUID(tag));
+        while (iterator.hasNext()) {
+            Tag nbtbase = (Tag) iterator.next();
+
+            this.addTrustedUUID(NbtUtils.loadUUID(nbtbase));
         }
 
         this.setSleeping(nbt.getBoolean("Sleeping"));
         this.setVariant(Fox.Type.byName(nbt.getString("Type")));
-        this.setSitting(nbt.getBoolean("Sitting"));
+        this.setSitting(nbt.getBoolean("Sitting"), false); // Paper - Add EntityToggleSitEvent
         this.setIsCrouching(nbt.getBoolean("Crouching"));
         if (this.level() instanceof ServerLevel) {
             this.setTargetGoals();
         }
+
     }
 
     public boolean isSitting() {
@@ -427,6 +445,12 @@
     }
 
     public void setSitting(boolean sitting) {
+        // Paper start - Add EntityToggleSitEvent
+        this.setSitting(sitting, true);
+    }
+    public void setSitting(boolean sitting, boolean fireEvent) {
+        if (fireEvent && !new io.papermc.paper.event.entity.EntityToggleSitEvent(this.getBukkitEntity(), sitting).callEvent()) return;
+        // Paper end - Add EntityToggleSitEvent
         this.setFlag(1, sitting);
     }
 
@@ -457,89 +481,98 @@
 
     private void setFlag(int mask, boolean value) {
         if (value) {
-            this.entityData.set(DATA_FLAGS_ID, (byte)(this.entityData.get(DATA_FLAGS_ID) | mask));
+            this.entityData.set(Fox.DATA_FLAGS_ID, (byte) ((Byte) this.entityData.get(Fox.DATA_FLAGS_ID) | mask));
         } else {
-            this.entityData.set(DATA_FLAGS_ID, (byte)(this.entityData.get(DATA_FLAGS_ID) & ~mask));
+            this.entityData.set(Fox.DATA_FLAGS_ID, (byte) ((Byte) this.entityData.get(Fox.DATA_FLAGS_ID) & ~mask));
         }
+
     }
 
     private boolean getFlag(int bitmask) {
-        return (this.entityData.get(DATA_FLAGS_ID) & bitmask) != 0;
+        return ((Byte) this.entityData.get(Fox.DATA_FLAGS_ID) & bitmask) != 0;
     }
 
     @Override
     public boolean canTakeItem(ItemStack stack) {
-        EquipmentSlot equipmentSlot = this.getEquipmentSlotForItem(stack);
-        return this.getItemBySlot(equipmentSlot).isEmpty() && equipmentSlot == EquipmentSlot.MAINHAND && super.canTakeItem(stack);
+        EquipmentSlot enumitemslot = this.getEquipmentSlotForItem(stack);
+
+        return !this.getItemBySlot(enumitemslot).isEmpty() ? false : enumitemslot == EquipmentSlot.MAINHAND && super.canTakeItem(stack);
     }
 
     @Override
     public boolean canHoldItem(ItemStack stack) {
-        ItemStack itemStack = this.getItemBySlot(EquipmentSlot.MAINHAND);
-        return itemStack.isEmpty() || this.ticksSinceEaten > 0 && stack.has(DataComponents.FOOD) && !itemStack.has(DataComponents.FOOD);
+        ItemStack itemstack1 = this.getItemBySlot(EquipmentSlot.MAINHAND);
+
+        return itemstack1.isEmpty() || this.ticksSinceEaten > 0 && stack.has(DataComponents.FOOD) && !itemstack1.has(DataComponents.FOOD);
     }
 
     private void spitOutItem(ItemStack stack) {
         if (!stack.isEmpty() && !this.level().isClientSide) {
-            ItemEntity itemEntity = new ItemEntity(
-                this.level(), this.getX() + this.getLookAngle().x, this.getY() + 1.0, this.getZ() + this.getLookAngle().z, stack
-            );
-            itemEntity.setPickUpDelay(40);
-            itemEntity.setThrower(this);
+            ItemEntity entityitem = new ItemEntity(this.level(), this.getX() + this.getLookAngle().x, this.getY() + 1.0D, this.getZ() + this.getLookAngle().z, stack);
+
+            entityitem.setPickUpDelay(40);
+            entityitem.setThrower(this);
             this.playSound(SoundEvents.FOX_SPIT, 1.0F, 1.0F);
-            this.level().addFreshEntity(itemEntity);
+            this.spawnAtLocation(entityitem); // Paper - Call EntityDropItemEvent
         }
     }
 
     private void dropItemStack(ItemStack stack) {
-        ItemEntity itemEntity = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), stack);
-        this.level().addFreshEntity(itemEntity);
+        ItemEntity entityitem = new ItemEntity(this.level(), this.getX(), this.getY(), this.getZ(), stack);
+
+        this.spawnAtLocation(entityitem); // Paper - Call EntityDropItemEvent
     }
 
     @Override
     protected void pickUpItem(ItemEntity item) {
-        ItemStack itemStack = item.getItem();
-        if (this.canHoldItem(itemStack)) {
-            int i = itemStack.getCount();
+        ItemStack itemstack = item.getItem();
+
+        if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityPickupItemEvent(this, item, itemstack.getCount() - 1, !this.canHoldItem(itemstack)).isCancelled()) { // CraftBukkit - call EntityPickupItemEvent
+            itemstack = item.getItem(); // CraftBukkit - update ItemStack from event
+            int i = itemstack.getCount();
+
             if (i > 1) {
-                this.dropItemStack(itemStack.split(i - 1));
+                this.dropItemStack(itemstack.split(i - 1));
             }
 
             this.spitOutItem(this.getItemBySlot(EquipmentSlot.MAINHAND));
             this.onItemPickup(item);
-            this.setItemSlot(EquipmentSlot.MAINHAND, itemStack.split(1));
+            this.setItemSlot(EquipmentSlot.MAINHAND, itemstack.split(1));
             this.setGuaranteedDrop(EquipmentSlot.MAINHAND);
-            this.take(item, itemStack.getCount());
-            item.discard();
+            this.take(item, itemstack.getCount());
+            item.discard(EntityRemoveEvent.Cause.PICKUP); // CraftBukkit - add Bukkit remove cause
             this.ticksSinceEaten = 0;
         }
+
     }
 
     @Override
     public void tick() {
         super.tick();
         if (this.isEffectiveAi()) {
-            boolean bl = this.isInWater();
-            if (bl || this.getTarget() != null || this.level().isThundering()) {
+            boolean flag = this.isInWater();
+
+            if (flag || this.getTarget() != null || this.level().isThundering()) {
                 this.wakeUp();
             }
 
-            if (bl || this.isSleeping()) {
+            if (flag || this.isSleeping()) {
                 this.setSitting(false);
             }
 
             if (this.isFaceplanted() && this.level().random.nextFloat() < 0.2F) {
-                BlockPos blockPos = this.blockPosition();
-                BlockState blockState = this.level().getBlockState(blockPos);
-                this.level().levelEvent(2001, blockPos, Block.getId(blockState));
+                BlockPos blockposition = this.blockPosition();
+                BlockState iblockdata = this.level().getBlockState(blockposition);
+
+                this.level().levelEvent(2001, blockposition, Block.getId(iblockdata));
             }
         }
 
         this.interestedAngleO = this.interestedAngle;
         if (this.isInterested()) {
-            this.interestedAngle = this.interestedAngle + (1.0F - this.interestedAngle) * 0.4F;
+            this.interestedAngle += (1.0F - this.interestedAngle) * 0.4F;
         } else {
-            this.interestedAngle = this.interestedAngle + (0.0F - this.interestedAngle) * 0.4F;
+            this.interestedAngle += (0.0F - this.interestedAngle) * 0.4F;
         }
 
         this.crouchAmountO = this.crouchAmount;
@@ -551,6 +584,7 @@
         } else {
             this.crouchAmount = 0.0F;
         }
+
     }
 
     @Override
@@ -560,7 +594,7 @@
 
     @Override
     protected void onOffspringSpawnedFromEgg(Player player, Mob child) {
-        ((Fox)child).addTrustedUUID(player.getUUID());
+        ((Fox) child).addTrustedUUID(player.getUUID());
     }
 
     public boolean isPouncing() {
@@ -597,7 +631,7 @@
     }
 
     public float getHeadRollAngle(float tickDelta) {
-        return Mth.lerp(tickDelta, this.interestedAngleO, this.interestedAngle) * 0.11F * (float) Math.PI;
+        return Mth.lerp(tickDelta, this.interestedAngleO, this.interestedAngle) * 0.11F * 3.1415927F;
     }
 
     public float getCrouchAmount(float tickDelta) {
@@ -632,12 +666,14 @@
 
     @Override
     public void playAmbientSound() {
-        SoundEvent soundEvent = this.getAmbientSound();
-        if (soundEvent == SoundEvents.FOX_SCREECH) {
-            this.playSound(soundEvent, 2.0F, this.getVoicePitch());
+        SoundEvent soundeffect = this.getAmbientSound();
+
+        if (soundeffect == SoundEvents.FOX_SCREECH) {
+            this.playSound(soundeffect, 2.0F, this.getVoicePitch());
         } else {
             super.playAmbientSound();
         }
+
     }
 
     @Nullable
@@ -647,8 +683,8 @@
             return SoundEvents.FOX_SLEEP;
         } else {
             if (!this.level().isDay() && this.random.nextFloat() < 0.1F) {
-                List<Player> list = this.level()
-                    .getEntitiesOfClass(Player.class, this.getBoundingBox().inflate(16.0, 16.0, 16.0), EntitySelector.NO_SPECTATORS);
+                List<Player> list = this.level().getEntitiesOfClass(Player.class, this.getBoundingBox().inflate(16.0D, 16.0D, 16.0D), EntitySelector.NO_SPECTATORS);
+
                 if (list.isEmpty()) {
                     return SoundEvents.FOX_SCREECH;
                 }
@@ -674,29 +710,52 @@
         return this.getTrustedUUIDs().contains(uuid);
     }
 
+    // Paper start - handle the bitten item separately like vanilla
     @Override
-    protected void dropAllDeathLoot(ServerLevel world, DamageSource damageSource) {
-        ItemStack itemStack = this.getItemBySlot(EquipmentSlot.MAINHAND);
-        if (!itemStack.isEmpty()) {
-            this.spawnAtLocation(itemStack);
+    protected boolean shouldSkipLoot(EquipmentSlot slot) {
+        return slot == EquipmentSlot.MAINHAND;
+    }
+    // Paper end
+
+    @Override
+    // Paper start - Cancellable death event
+    protected org.bukkit.event.entity.EntityDeathEvent dropAllDeathLoot(ServerLevel world, DamageSource damageSource) {
+        ItemStack itemstack = this.getItemBySlot(EquipmentSlot.MAINHAND);
+
+        boolean releaseMouth = false;
+        if (!itemstack.isEmpty() && this.level().getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) { // Fix MC-153010
+            this.spawnAtLocation(itemstack);
+            releaseMouth = true;
+        }
+
+        org.bukkit.event.entity.EntityDeathEvent deathEvent = super.dropAllDeathLoot(world, damageSource);
+
+        // Below is code to drop
+
+        if (deathEvent == null || deathEvent.isCancelled()) {
+            return deathEvent;
+        }
+
+        if (releaseMouth) {
+            // Paper end - Cancellable death event
             this.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY);
         }
 
-        super.dropAllDeathLoot(world, damageSource);
+        return deathEvent; // Paper - Cancellable death event
     }
 
     public static boolean isPathClear(Fox fox, LivingEntity chasedEntity) {
-        double d = chasedEntity.getZ() - fox.getZ();
-        double e = chasedEntity.getX() - fox.getX();
-        double f = d / e;
-        int i = 6;
+        double d0 = chasedEntity.getZ() - fox.getZ();
+        double d1 = chasedEntity.getX() - fox.getX();
+        double d2 = d0 / d1;
+        boolean flag = true;
 
-        for (int j = 0; j < 6; j++) {
-            double g = f == 0.0 ? 0.0 : d * (double)((float)j / 6.0F);
-            double h = f == 0.0 ? e * (double)((float)j / 6.0F) : g / f;
+        for (int i = 0; i < 6; ++i) {
+            double d3 = d2 == 0.0D ? 0.0D : d0 * (double) ((float) i / 6.0F);
+            double d4 = d2 == 0.0D ? d1 * (double) ((float) i / 6.0F) : d3 / d2;
 
-            for (int k = 1; k < 4; k++) {
-                if (!fox.level().getBlockState(BlockPos.containing(fox.getX() + h, fox.getY() + (double)k, fox.getZ() + g)).canBeReplaced()) {
+            for (int j = 1; j < 4; ++j) {
+                if (!fox.level().getBlockState(BlockPos.containing(fox.getX() + d4, fox.getY() + (double) j, fox.getZ() + d3)).canBeReplaced()) {
                     return false;
                 }
             }
@@ -707,61 +766,64 @@
 
     @Override
     public Vec3 getLeashOffset() {
-        return new Vec3(0.0, (double)(0.55F * this.getEyeHeight()), (double)(this.getBbWidth() * 0.4F));
+        return new Vec3(0.0D, (double) (0.55F * this.getEyeHeight()), (double) (this.getBbWidth() * 0.4F));
     }
 
-    class DefendTrustedTargetGoal extends NearestAttackableTargetGoal<LivingEntity> {
-        @Nullable
-        private LivingEntity trustedLastHurtBy;
-        @Nullable
-        private LivingEntity trustedLastHurt;
-        private int timestamp;
+    public class FoxLookControl extends LookControl {
 
-        public DefendTrustedTargetGoal(
-            final Class<LivingEntity> targetEntityClass,
-            final boolean checkVisibility,
-            final boolean checkCanNavigate,
-            @Nullable final Predicate<LivingEntity> targetPredicate
-        ) {
-            super(Fox.this, targetEntityClass, 10, checkVisibility, checkCanNavigate, targetPredicate);
+        public FoxLookControl() {
+            super(Fox.this);
         }
 
         @Override
-        public boolean canUse() {
-            if (this.randomInterval > 0 && this.mob.getRandom().nextInt(this.randomInterval) != 0) {
-                return false;
-            } else {
-                for (UUID uUID : Fox.this.getTrustedUUIDs()) {
-                    if (uUID != null
-                        && Fox.this.level() instanceof ServerLevel
-                        && ((ServerLevel)Fox.this.level()).getEntity(uUID) instanceof LivingEntity livingEntity) {
-                        this.trustedLastHurt = livingEntity;
-                        this.trustedLastHurtBy = livingEntity.getLastHurtByMob();
-                        int i = livingEntity.getLastHurtByMobTimestamp();
-                        return i != this.timestamp && this.canAttack(this.trustedLastHurtBy, this.targetConditions);
-                    }
-                }
-
-                return false;
+        public void tick() {
+            if (!Fox.this.isSleeping()) {
+                super.tick();
             }
+
         }
 
         @Override
-        public void start() {
-            this.setTarget(this.trustedLastHurtBy);
-            this.target = this.trustedLastHurtBy;
-            if (this.trustedLastHurt != null) {
-                this.timestamp = this.trustedLastHurt.getLastHurtByMobTimestamp();
+        protected boolean resetXRotOnTick() {
+            return !Fox.this.isPouncing() && !Fox.this.isCrouching() && !Fox.this.isInterested() && !Fox.this.isFaceplanted();
+        }
+    }
+
+    private class FoxMoveControl extends MoveControl {
+
+        public FoxMoveControl() {
+            super(Fox.this);
+        }
+
+        @Override
+        public void tick() {
+            if (Fox.this.canMove()) {
+                super.tick();
             }
 
-            Fox.this.playSound(SoundEvents.FOX_AGGRO, 1.0F, 1.0F);
-            Fox.this.setDefending(true);
-            Fox.this.wakeUp();
+        }
+    }
+
+    private class FoxFloatGoal extends FloatGoal {
+
+        public FoxFloatGoal() {
+            super(Fox.this);
+        }
+
+        @Override
+        public void start() {
             super.start();
+            Fox.this.clearStates();
+        }
+
+        @Override
+        public boolean canUse() {
+            return Fox.this.isInWater() && Fox.this.getFluidHeight(FluidTags.WATER) > 0.25D || Fox.this.isInLava();
         }
     }
 
-    class FaceplantGoal extends Goal {
+    private class FaceplantGoal extends Goal {
+
         int countdown;
 
         public FaceplantGoal() {
@@ -790,419 +852,514 @@
 
         @Override
         public void tick() {
-            this.countdown--;
-        }
-    }
-
-    public class FoxAlertableEntitiesSelector implements Predicate<LivingEntity> {
-        @Override
-        public boolean test(LivingEntity livingEntity) {
-            if (livingEntity instanceof Fox) {
-                return false;
-            } else if (livingEntity instanceof Chicken || livingEntity instanceof Rabbit || livingEntity instanceof Monster) {
-                return true;
-            } else {
-                return livingEntity instanceof TamableAnimal
-                    ? !((TamableAnimal)livingEntity).isTame()
-                    : (!(livingEntity instanceof Player) || !livingEntity.isSpectator() && !((Player)livingEntity).isCreative())
-                        && !Fox.this.trusts(livingEntity.getUUID())
-                        && !livingEntity.isSleeping()
-                        && !livingEntity.isDiscrete();
-            }
+            --this.countdown;
         }
     }
 
-    abstract class FoxBehaviorGoal extends Goal {
-        private final TargetingConditions alertableTargeting = TargetingConditions.forCombat()
-            .range(12.0)
-            .ignoreLineOfSight()
-            .selector(Fox.this.new FoxAlertableEntitiesSelector());
+    private class FoxPanicGoal extends PanicGoal {
 
-        protected boolean hasShelter() {
-            BlockPos blockPos = BlockPos.containing(Fox.this.getX(), Fox.this.getBoundingBox().maxY, Fox.this.getZ());
-            return !Fox.this.level().canSeeSky(blockPos) && Fox.this.getWalkTargetValue(blockPos) >= 0.0F;
+        public FoxPanicGoal(final double d0) {
+            super(Fox.this, d0);
         }
 
-        protected boolean alertable() {
-            return !Fox.this.level()
-                .getNearbyEntities(LivingEntity.class, this.alertableTargeting, Fox.this, Fox.this.getBoundingBox().inflate(12.0, 6.0, 12.0))
-                .isEmpty();
+        @Override
+        public boolean shouldPanic() {
+            return !Fox.this.isDefending() && super.shouldPanic();
         }
     }
 
-    class FoxBreedGoal extends BreedGoal {
-        public FoxBreedGoal(final double chance) {
-            super(Fox.this, chance);
+    private class FoxBreedGoal extends BreedGoal {
+
+        public FoxBreedGoal(final Fox chance, final double fox) {
+            super(chance, fox);
         }
 
         @Override
         public void start() {
-            ((Fox)this.animal).clearStates();
-            ((Fox)this.partner).clearStates();
+            ((Fox) this.animal).clearStates();
+            ((Fox) this.partner).clearStates();
             super.start();
         }
 
         @Override
         protected void breed() {
-            ServerLevel serverLevel = (ServerLevel)this.level;
-            Fox fox = (Fox)this.animal.getBreedOffspring(serverLevel, this.partner);
-            if (fox != null) {
-                ServerPlayer serverPlayer = this.animal.getLoveCause();
-                ServerPlayer serverPlayer2 = this.partner.getLoveCause();
-                ServerPlayer serverPlayer3 = serverPlayer;
-                if (serverPlayer != null) {
-                    fox.addTrustedUUID(serverPlayer.getUUID());
+            ServerLevel worldserver = (ServerLevel) this.level;
+            Fox entityfox = (Fox) this.animal.getBreedOffspring(worldserver, this.partner);
+
+            if (entityfox != null) {
+                ServerPlayer entityplayer = this.animal.getLoveCause();
+                ServerPlayer entityplayer1 = this.partner.getLoveCause();
+                ServerPlayer entityplayer2 = entityplayer;
+
+                if (entityplayer != null) {
+                    entityfox.addTrustedUUID(entityplayer.getUUID());
                 } else {
-                    serverPlayer3 = serverPlayer2;
+                    entityplayer2 = entityplayer1;
                 }
 
-                if (serverPlayer2 != null && serverPlayer != serverPlayer2) {
-                    fox.addTrustedUUID(serverPlayer2.getUUID());
+                if (entityplayer1 != null && entityplayer != entityplayer1) {
+                    entityfox.addTrustedUUID(entityplayer1.getUUID());
                 }
+                // CraftBukkit start - call EntityBreedEvent
+                entityfox.setAge(-24000);
+                entityfox.moveTo(this.animal.getX(), this.animal.getY(), this.animal.getZ(), 0.0F, 0.0F);
+                int experience = this.animal.getRandom().nextInt(7) + 1;
+                org.bukkit.event.entity.EntityBreedEvent entityBreedEvent = org.bukkit.craftbukkit.event.CraftEventFactory.callEntityBreedEvent(entityfox, this.animal, this.partner, entityplayer, this.animal.breedItem, experience);
+                if (entityBreedEvent.isCancelled()) {
+                    return;
+                }
+                experience = entityBreedEvent.getExperience();
+                // CraftBukkit end
 
-                if (serverPlayer3 != null) {
-                    serverPlayer3.awardStat(Stats.ANIMALS_BRED);
-                    CriteriaTriggers.BRED_ANIMALS.trigger(serverPlayer3, this.animal, this.partner, fox);
+                if (entityplayer2 != null) {
+                    entityplayer2.awardStat(Stats.ANIMALS_BRED);
+                    CriteriaTriggers.BRED_ANIMALS.trigger(entityplayer2, this.animal, this.partner, entityfox);
                 }
 
                 this.animal.setAge(6000);
                 this.partner.setAge(6000);
                 this.animal.resetLove();
                 this.partner.resetLove();
-                fox.setAge(-24000);
-                fox.moveTo(this.animal.getX(), this.animal.getY(), this.animal.getZ(), 0.0F, 0.0F);
-                serverLevel.addFreshEntityWithPassengers(fox);
-                this.level.broadcastEntityEvent(this.animal, (byte)18);
+                worldserver.addFreshEntityWithPassengers(entityfox, org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason.BREEDING); // CraftBukkit - added SpawnReason
+                this.level.broadcastEntityEvent(this.animal, (byte) 18);
                 if (this.level.getGameRules().getBoolean(GameRules.RULE_DOMOBLOOT)) {
-                    this.level
-                        .addFreshEntity(
-                            new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), this.animal.getRandom().nextInt(7) + 1)
-                        );
+                    // CraftBukkit start - use event experience
+                    if (experience > 0) {
+                        this.level.addFreshEntity(new ExperienceOrb(this.level, this.animal.getX(), this.animal.getY(), this.animal.getZ(), experience, org.bukkit.entity.ExperienceOrb.SpawnReason.BREED, entityplayer, entityfox)); // Paper
+                    }
+                    // CraftBukkit end
                 }
+
             }
         }
     }
 
-    public class FoxEatBerriesGoal extends MoveToBlockGoal {
-        private static final int WAIT_TICKS = 40;
-        protected int ticksWaited;
+    private class StalkPreyGoal extends Goal {
 
-        public FoxEatBerriesGoal(final double speed, final int range, final int maxYDifference) {
-            super(Fox.this, speed, range, maxYDifference);
+        public StalkPreyGoal() {
+            this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
         }
 
         @Override
-        public double acceptedDistance() {
-            return 2.0;
+        public boolean canUse() {
+            if (Fox.this.isSleeping()) {
+                return false;
+            } else {
+                LivingEntity entityliving = Fox.this.getTarget();
+
+                return entityliving != null && entityliving.isAlive() && Fox.STALKABLE_PREY.test(entityliving) && Fox.this.distanceToSqr((Entity) entityliving) > 36.0D && !Fox.this.isCrouching() && !Fox.this.isInterested() && !Fox.this.jumping;
+            }
         }
 
         @Override
-        public boolean shouldRecalculatePath() {
-            return this.tryTicks % 100 == 0;
+        public void start() {
+            Fox.this.setSitting(false);
+            Fox.this.setFaceplanted(false);
         }
 
         @Override
-        protected boolean isValidTarget(LevelReader world, BlockPos pos) {
-            BlockState blockState = world.getBlockState(pos);
-            return blockState.is(Blocks.SWEET_BERRY_BUSH) && blockState.getValue(SweetBerryBushBlock.AGE) >= 2 || CaveVines.hasGlowBerries(blockState);
+        public void stop() {
+            LivingEntity entityliving = Fox.this.getTarget();
+
+            if (entityliving != null && Fox.isPathClear(Fox.this, entityliving)) {
+                Fox.this.setIsInterested(true);
+                Fox.this.setIsCrouching(true);
+                Fox.this.getNavigation().stop();
+                Fox.this.getLookControl().setLookAt(entityliving, (float) Fox.this.getMaxHeadYRot(), (float) Fox.this.getMaxHeadXRot());
+            } else {
+                Fox.this.setIsInterested(false);
+                Fox.this.setIsCrouching(false);
+            }
+
         }
 
         @Override
         public void tick() {
-            if (this.isReachedTarget()) {
-                if (this.ticksWaited >= 40) {
-                    this.onReachedTarget();
+            LivingEntity entityliving = Fox.this.getTarget();
+
+            if (entityliving != null) {
+                Fox.this.getLookControl().setLookAt(entityliving, (float) Fox.this.getMaxHeadYRot(), (float) Fox.this.getMaxHeadXRot());
+                if (Fox.this.distanceToSqr((Entity) entityliving) <= 36.0D) {
+                    Fox.this.setIsInterested(true);
+                    Fox.this.setIsCrouching(true);
+                    Fox.this.getNavigation().stop();
                 } else {
-                    this.ticksWaited++;
+                    Fox.this.getNavigation().moveTo((Entity) entityliving, 1.5D);
                 }
-            } else if (!this.isReachedTarget() && Fox.this.random.nextFloat() < 0.05F) {
-                Fox.this.playSound(SoundEvents.FOX_SNIFF, 1.0F, 1.0F);
-            }
 
-            super.tick();
+            }
         }
+    }
 
-        protected void onReachedTarget() {
-            if (Fox.this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
-                BlockState blockState = Fox.this.level().getBlockState(this.blockPos);
-                if (blockState.is(Blocks.SWEET_BERRY_BUSH)) {
-                    this.pickSweetBerries(blockState);
-                } else if (CaveVines.hasGlowBerries(blockState)) {
-                    this.pickGlowBerry(blockState);
+    public class FoxPounceGoal extends JumpGoal {
+
+        public FoxPounceGoal() {}
+
+        @Override
+        public boolean canUse() {
+            if (!Fox.this.isFullyCrouched()) {
+                return false;
+            } else {
+                LivingEntity entityliving = Fox.this.getTarget();
+
+                if (entityliving != null && entityliving.isAlive()) {
+                    if (entityliving.getMotionDirection() != entityliving.getDirection()) {
+                        return false;
+                    } else {
+                        boolean flag = Fox.isPathClear(Fox.this, entityliving);
+
+                        if (!flag) {
+                            Fox.this.getNavigation().createPath((Entity) entityliving, 0);
+                            Fox.this.setIsCrouching(false);
+                            Fox.this.setIsInterested(false);
+                        }
+
+                        return flag;
+                    }
+                } else {
+                    return false;
                 }
             }
         }
 
-        private void pickGlowBerry(BlockState state) {
-            CaveVines.use(Fox.this, state, Fox.this.level(), this.blockPos);
-        }
+        @Override
+        public boolean canContinueToUse() {
+            LivingEntity entityliving = Fox.this.getTarget();
 
-        private void pickSweetBerries(BlockState state) {
-            int i = state.getValue(SweetBerryBushBlock.AGE);
-            state.setValue(SweetBerryBushBlock.AGE, Integer.valueOf(1));
-            int j = 1 + Fox.this.level().random.nextInt(2) + (i == 3 ? 1 : 0);
-            ItemStack itemStack = Fox.this.getItemBySlot(EquipmentSlot.MAINHAND);
-            if (itemStack.isEmpty()) {
-                Fox.this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.SWEET_BERRIES));
-                j--;
-            }
+            if (entityliving != null && entityliving.isAlive()) {
+                double d0 = Fox.this.getDeltaMovement().y;
 
-            if (j > 0) {
-                Block.popResource(Fox.this.level(), this.blockPos, new ItemStack(Items.SWEET_BERRIES, j));
+                return (d0 * d0 >= 0.05000000074505806D || Math.abs(Fox.this.getXRot()) >= 15.0F || !Fox.this.onGround()) && !Fox.this.isFaceplanted();
+            } else {
+                return false;
             }
-
-            Fox.this.playSound(SoundEvents.SWEET_BERRY_BUSH_PICK_BERRIES, 1.0F, 1.0F);
-            Fox.this.level().setBlock(this.blockPos, state.setValue(SweetBerryBushBlock.AGE, Integer.valueOf(1)), 2);
-            Fox.this.level().gameEvent(GameEvent.BLOCK_CHANGE, this.blockPos, GameEvent.Context.of(Fox.this));
         }
 
         @Override
-        public boolean canUse() {
-            return !Fox.this.isSleeping() && super.canUse();
+        public boolean isInterruptable() {
+            return false;
         }
 
         @Override
         public void start() {
-            this.ticksWaited = 0;
-            Fox.this.setSitting(false);
-            super.start();
-        }
-    }
+            Fox.this.setJumping(true);
+            Fox.this.setIsPouncing(true);
+            Fox.this.setIsInterested(false);
+            LivingEntity entityliving = Fox.this.getTarget();
 
-    class FoxFloatGoal extends FloatGoal {
-        public FoxFloatGoal() {
-            super(Fox.this);
+            if (entityliving != null) {
+                Fox.this.getLookControl().setLookAt(entityliving, 60.0F, 30.0F);
+                Vec3 vec3d = (new Vec3(entityliving.getX() - Fox.this.getX(), entityliving.getY() - Fox.this.getY(), entityliving.getZ() - Fox.this.getZ())).normalize();
+
+                Fox.this.setDeltaMovement(Fox.this.getDeltaMovement().add(vec3d.x * 0.8D, 0.9D, vec3d.z * 0.8D));
+            }
+
+            Fox.this.getNavigation().stop();
         }
 
         @Override
-        public void start() {
-            super.start();
-            Fox.this.clearStates();
+        public void stop() {
+            Fox.this.setIsCrouching(false);
+            Fox.this.crouchAmount = 0.0F;
+            Fox.this.crouchAmountO = 0.0F;
+            Fox.this.setIsInterested(false);
+            Fox.this.setIsPouncing(false);
         }
 
         @Override
-        public boolean canUse() {
-            return Fox.this.isInWater() && Fox.this.getFluidHeight(FluidTags.WATER) > 0.25 || Fox.this.isInLava();
+        public void tick() {
+            LivingEntity entityliving = Fox.this.getTarget();
+
+            if (entityliving != null) {
+                Fox.this.getLookControl().setLookAt(entityliving, 60.0F, 30.0F);
+            }
+
+            if (!Fox.this.isFaceplanted()) {
+                Vec3 vec3d = Fox.this.getDeltaMovement();
+
+                if (vec3d.y * vec3d.y < 0.029999999329447746D && Fox.this.getXRot() != 0.0F) {
+                    Fox.this.setXRot(Mth.rotLerp(0.2F, Fox.this.getXRot(), 0.0F));
+                } else {
+                    double d0 = vec3d.horizontalDistance();
+                    double d1 = Math.signum(-vec3d.y) * Math.acos(d0 / vec3d.length()) * 57.2957763671875D;
+
+                    Fox.this.setXRot((float) d1);
+                }
+            }
+
+            if (entityliving != null && Fox.this.distanceTo(entityliving) <= 2.0F) {
+                Fox.this.doHurtTarget(entityliving);
+            } else if (Fox.this.getXRot() > 0.0F && Fox.this.onGround() && (float) Fox.this.getDeltaMovement().y != 0.0F && Fox.this.level().getBlockState(Fox.this.blockPosition()).is(Blocks.SNOW)) {
+                Fox.this.setXRot(60.0F);
+                Fox.this.setTarget((LivingEntity) null);
+                Fox.this.setFaceplanted(true);
+            }
+
         }
     }
 
-    class FoxFollowParentGoal extends FollowParentGoal {
-        private final Fox fox;
+    private class SeekShelterGoal extends FleeSunGoal {
 
-        public FoxFollowParentGoal(final Fox fox, final double speed) {
-            super(fox, speed);
-            this.fox = fox;
+        private int interval = reducedTickDelay(100);
+
+        public SeekShelterGoal(final double d0) {
+            super(Fox.this, d0);
         }
 
         @Override
         public boolean canUse() {
-            return !this.fox.isDefending() && super.canUse();
-        }
+            if (!Fox.this.isSleeping() && this.mob.getTarget() == null) {
+                if (Fox.this.level().isThundering() && Fox.this.level().canSeeSky(this.mob.blockPosition())) {
+                    return this.setWantedPos();
+                } else if (this.interval > 0) {
+                    --this.interval;
+                    return false;
+                } else {
+                    this.interval = 100;
+                    BlockPos blockposition = this.mob.blockPosition();
 
-        @Override
-        public boolean canContinueToUse() {
-            return !this.fox.isDefending() && super.canContinueToUse();
+                    return Fox.this.level().isDay() && Fox.this.level().canSeeSky(blockposition) && !((ServerLevel) Fox.this.level()).isVillage(blockposition) && this.setWantedPos();
+                }
+            } else {
+                return false;
+            }
         }
 
         @Override
         public void start() {
-            this.fox.clearStates();
+            Fox.this.clearStates();
             super.start();
         }
     }
 
-    public static class FoxGroupData extends AgeableMob.AgeableMobGroupData {
-        public final Fox.Type type;
+    private class FoxMeleeAttackGoal extends MeleeAttackGoal {
 
-        public FoxGroupData(Fox.Type type) {
-            super(false);
-            this.type = type;
+        public FoxMeleeAttackGoal(final double d0, final boolean flag) {
+            super(Fox.this, d0, flag);
         }
-    }
 
-    class FoxLookAtPlayerGoal extends LookAtPlayerGoal {
-        public FoxLookAtPlayerGoal(final Mob fox, final Class<? extends LivingEntity> targetType, final float range) {
-            super(fox, targetType, range);
+        @Override
+        protected void checkAndPerformAttack(LivingEntity target) {
+            if (this.canPerformAttack(target)) {
+                this.resetAttackCooldown();
+                this.mob.doHurtTarget(target);
+                Fox.this.playSound(SoundEvents.FOX_BITE, 1.0F, 1.0F);
+            }
+
         }
 
         @Override
-        public boolean canUse() {
-            return super.canUse() && !Fox.this.isFaceplanted() && !Fox.this.isInterested();
+        public void start() {
+            Fox.this.setIsInterested(false);
+            super.start();
         }
 
         @Override
-        public boolean canContinueToUse() {
-            return super.canContinueToUse() && !Fox.this.isFaceplanted() && !Fox.this.isInterested();
+        public boolean canUse() {
+            return !Fox.this.isSitting() && !Fox.this.isSleeping() && !Fox.this.isCrouching() && !Fox.this.isFaceplanted() && super.canUse();
         }
     }
 
-    public class FoxLookControl extends LookControl {
-        public FoxLookControl() {
-            super(Fox.this);
+    private class SleepGoal extends Fox.FoxBehaviorGoal {
+
+        private static final int WAIT_TIME_BEFORE_SLEEP = reducedTickDelay(140);
+        private int countdown;
+
+        public SleepGoal() {
+            super();
+            this.countdown = Fox.this.random.nextInt(Fox.SleepGoal.WAIT_TIME_BEFORE_SLEEP);
+            this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK, Goal.Flag.JUMP));
         }
 
         @Override
-        public void tick() {
-            if (!Fox.this.isSleeping()) {
-                super.tick();
-            }
+        public boolean canUse() {
+            return Fox.this.xxa == 0.0F && Fox.this.yya == 0.0F && Fox.this.zza == 0.0F ? this.canSleep() || Fox.this.isSleeping() : false;
         }
 
         @Override
-        protected boolean resetXRotOnTick() {
-            return !Fox.this.isPouncing() && !Fox.this.isCrouching() && !Fox.this.isInterested() && !Fox.this.isFaceplanted();
+        public boolean canContinueToUse() {
+            return this.canSleep();
         }
-    }
 
-    class FoxMeleeAttackGoal extends MeleeAttackGoal {
-        public FoxMeleeAttackGoal(final double speed, final boolean pauseWhenIdle) {
-            super(Fox.this, speed, pauseWhenIdle);
+        private boolean canSleep() {
+            if (this.countdown > 0) {
+                --this.countdown;
+                return false;
+            } else {
+                return Fox.this.level().isDay() && this.hasShelter() && !this.alertable() && !Fox.this.isInPowderSnow;
+            }
         }
 
         @Override
-        protected void checkAndPerformAttack(LivingEntity target) {
-            if (this.canPerformAttack(target)) {
-                this.resetAttackCooldown();
-                this.mob.doHurtTarget(target);
-                Fox.this.playSound(SoundEvents.FOX_BITE, 1.0F, 1.0F);
-            }
+        public void stop() {
+            this.countdown = Fox.this.random.nextInt(Fox.SleepGoal.WAIT_TIME_BEFORE_SLEEP);
+            Fox.this.clearStates();
         }
 
         @Override
         public void start() {
+            Fox.this.setSitting(false);
+            Fox.this.setIsCrouching(false);
             Fox.this.setIsInterested(false);
-            super.start();
+            Fox.this.setJumping(false);
+            Fox.this.setSleeping(true);
+            Fox.this.getNavigation().stop();
+            Fox.this.getMoveControl().setWantedPosition(Fox.this.getX(), Fox.this.getY(), Fox.this.getZ(), 0.0D);
+        }
+    }
+
+    private class FoxFollowParentGoal extends FollowParentGoal {
+
+        private final Fox fox;
+
+        public FoxFollowParentGoal(final Fox fox, final Fox speed, final double d0) {
+            super(speed, d0);
+            this.fox = speed;
         }
 
         @Override
         public boolean canUse() {
-            return !Fox.this.isSitting() && !Fox.this.isSleeping() && !Fox.this.isCrouching() && !Fox.this.isFaceplanted() && super.canUse();
+            return !this.fox.isDefending() && super.canUse();
         }
-    }
 
-    class FoxMoveControl extends MoveControl {
-        public FoxMoveControl() {
-            super(Fox.this);
+        @Override
+        public boolean canContinueToUse() {
+            return !this.fox.isDefending() && super.canContinueToUse();
         }
 
         @Override
-        public void tick() {
-            if (Fox.this.canMove()) {
-                super.tick();
-            }
+        public void start() {
+            this.fox.clearStates();
+            super.start();
         }
     }
 
-    class FoxPanicGoal extends PanicGoal {
-        public FoxPanicGoal(final double speed) {
-            super(Fox.this, speed);
+    private class FoxStrollThroughVillageGoal extends StrollThroughVillageGoal {
+
+        public FoxStrollThroughVillageGoal(final int i, final int j) {
+            super(Fox.this, j);
         }
 
         @Override
-        public boolean shouldPanic() {
-            return !Fox.this.isDefending() && super.shouldPanic();
+        public void start() {
+            Fox.this.clearStates();
+            super.start();
         }
-    }
 
-    public class FoxPounceGoal extends JumpGoal {
         @Override
         public boolean canUse() {
-            if (!Fox.this.isFullyCrouched()) {
-                return false;
-            } else {
-                LivingEntity livingEntity = Fox.this.getTarget();
-                if (livingEntity != null && livingEntity.isAlive()) {
-                    if (livingEntity.getMotionDirection() != livingEntity.getDirection()) {
-                        return false;
-                    } else {
-                        boolean bl = Fox.isPathClear(Fox.this, livingEntity);
-                        if (!bl) {
-                            Fox.this.getNavigation().createPath(livingEntity, 0);
-                            Fox.this.setIsCrouching(false);
-                            Fox.this.setIsInterested(false);
-                        }
-
-                        return bl;
-                    }
-                } else {
-                    return false;
-                }
-            }
+            return super.canUse() && this.canFoxMove();
         }
 
         @Override
         public boolean canContinueToUse() {
-            LivingEntity livingEntity = Fox.this.getTarget();
-            if (livingEntity != null && livingEntity.isAlive()) {
-                double d = Fox.this.getDeltaMovement().y;
-                return (!(d * d < 0.05F) || !(Math.abs(Fox.this.getXRot()) < 15.0F) || !Fox.this.onGround()) && !Fox.this.isFaceplanted();
-            } else {
-                return false;
-            }
+            return super.canContinueToUse() && this.canFoxMove();
         }
 
-        @Override
-        public boolean isInterruptable() {
-            return false;
+        private boolean canFoxMove() {
+            return !Fox.this.isSleeping() && !Fox.this.isSitting() && !Fox.this.isDefending() && Fox.this.getTarget() == null;
+        }
+    }
+
+    public class FoxEatBerriesGoal extends MoveToBlockGoal {
+
+        private static final int WAIT_TICKS = 40;
+        protected int ticksWaited;
+
+        public FoxEatBerriesGoal(final double d0, final int i, final int j) {
+            super(Fox.this, d0, i, j);
         }
 
         @Override
-        public void start() {
-            Fox.this.setJumping(true);
-            Fox.this.setIsPouncing(true);
-            Fox.this.setIsInterested(false);
-            LivingEntity livingEntity = Fox.this.getTarget();
-            if (livingEntity != null) {
-                Fox.this.getLookControl().setLookAt(livingEntity, 60.0F, 30.0F);
-                Vec3 vec3 = new Vec3(livingEntity.getX() - Fox.this.getX(), livingEntity.getY() - Fox.this.getY(), livingEntity.getZ() - Fox.this.getZ())
-                    .normalize();
-                Fox.this.setDeltaMovement(Fox.this.getDeltaMovement().add(vec3.x * 0.8, 0.9, vec3.z * 0.8));
-            }
+        public double acceptedDistance() {
+            return 2.0D;
+        }
 
-            Fox.this.getNavigation().stop();
+        @Override
+        public boolean shouldRecalculatePath() {
+            return this.tryTicks % 100 == 0;
         }
 
         @Override
-        public void stop() {
-            Fox.this.setIsCrouching(false);
-            Fox.this.crouchAmount = 0.0F;
-            Fox.this.crouchAmountO = 0.0F;
-            Fox.this.setIsInterested(false);
-            Fox.this.setIsPouncing(false);
+        protected boolean isValidTarget(LevelReader world, BlockPos pos) {
+            BlockState iblockdata = world.getBlockState(pos);
+
+            return iblockdata.is(Blocks.SWEET_BERRY_BUSH) && (Integer) iblockdata.getValue(SweetBerryBushBlock.AGE) >= 2 || CaveVines.hasGlowBerries(iblockdata);
         }
 
         @Override
         public void tick() {
-            LivingEntity livingEntity = Fox.this.getTarget();
-            if (livingEntity != null) {
-                Fox.this.getLookControl().setLookAt(livingEntity, 60.0F, 30.0F);
+            if (this.isReachedTarget()) {
+                if (this.ticksWaited >= 40) {
+                    this.onReachedTarget();
+                } else {
+                    ++this.ticksWaited;
+                }
+            } else if (!this.isReachedTarget() && Fox.this.random.nextFloat() < 0.05F) {
+                Fox.this.playSound(SoundEvents.FOX_SNIFF, 1.0F, 1.0F);
             }
 
-            if (!Fox.this.isFaceplanted()) {
-                Vec3 vec3 = Fox.this.getDeltaMovement();
-                if (vec3.y * vec3.y < 0.03F && Fox.this.getXRot() != 0.0F) {
-                    Fox.this.setXRot(Mth.rotLerp(0.2F, Fox.this.getXRot(), 0.0F));
-                } else {
-                    double d = vec3.horizontalDistance();
-                    double e = Math.signum(-vec3.y) * Math.acos(d / vec3.length()) * 180.0F / (float)Math.PI;
-                    Fox.this.setXRot((float)e);
+            super.tick();
+        }
+
+        protected void onReachedTarget() {
+            if (Fox.this.level().getGameRules().getBoolean(GameRules.RULE_MOBGRIEFING)) {
+                BlockState iblockdata = Fox.this.level().getBlockState(this.blockPos);
+
+                if (iblockdata.is(Blocks.SWEET_BERRY_BUSH)) {
+                    this.pickSweetBerries(iblockdata);
+                } else if (CaveVines.hasGlowBerries(iblockdata)) {
+                    this.pickGlowBerry(iblockdata);
                 }
+
             }
+        }
 
-            if (livingEntity != null && Fox.this.distanceTo(livingEntity) <= 2.0F) {
-                Fox.this.doHurtTarget(livingEntity);
-            } else if (Fox.this.getXRot() > 0.0F
-                && Fox.this.onGround()
-                && (float)Fox.this.getDeltaMovement().y != 0.0F
-                && Fox.this.level().getBlockState(Fox.this.blockPosition()).is(Blocks.SNOW)) {
-                Fox.this.setXRot(60.0F);
-                Fox.this.setTarget(null);
-                Fox.this.setFaceplanted(true);
+        private void pickGlowBerry(BlockState state) {
+            CaveVines.use(Fox.this, state, Fox.this.level(), this.blockPos);
+        }
+
+        private void pickSweetBerries(BlockState state) {
+            int i = (Integer) state.getValue(SweetBerryBushBlock.AGE);
+
+            state.setValue(SweetBerryBushBlock.AGE, 1);
+            // CraftBukkit start - call EntityChangeBlockEvent
+            if (!org.bukkit.craftbukkit.event.CraftEventFactory.callEntityChangeBlockEvent(Fox.this, this.blockPos, state.setValue(SweetBerryBushBlock.AGE, 1))) {
+                return;
+            }
+            // CraftBukkit end
+            int j = 1 + Fox.this.level().random.nextInt(2) + (i == 3 ? 1 : 0);
+            ItemStack itemstack = Fox.this.getItemBySlot(EquipmentSlot.MAINHAND);
+
+            if (itemstack.isEmpty()) {
+                Fox.this.setItemSlot(EquipmentSlot.MAINHAND, new ItemStack(Items.SWEET_BERRIES));
+                --j;
             }
+
+            if (j > 0) {
+                Block.popResource(Fox.this.level(), this.blockPos, new ItemStack(Items.SWEET_BERRIES, j));
+            }
+
+            Fox.this.playSound(SoundEvents.SWEET_BERRY_BUSH_PICK_BERRIES, 1.0F, 1.0F);
+            Fox.this.level().setBlock(this.blockPos, (BlockState) state.setValue(SweetBerryBushBlock.AGE, 1), 2);
+            Fox.this.level().gameEvent((Holder) GameEvent.BLOCK_CHANGE, this.blockPos, GameEvent.Context.of((Entity) Fox.this));
+        }
+
+        @Override
+        public boolean canUse() {
+            return !Fox.this.isSleeping() && super.canUse();
+        }
+
+        @Override
+        public void start() {
+            this.ticksWaited = 0;
+            Fox.this.setSitting(false);
+            super.start();
         }
     }
 
-    class FoxSearchForItemsGoal extends Goal {
+    private class FoxSearchForItemsGoal extends Goal {
+
         public FoxSearchForItemsGoal() {
             this.setFlags(EnumSet.of(Goal.Flag.MOVE));
         }
@@ -1211,83 +1368,75 @@
         public boolean canUse() {
             if (!Fox.this.getItemBySlot(EquipmentSlot.MAINHAND).isEmpty()) {
                 return false;
-            } else if (Fox.this.getTarget() != null || Fox.this.getLastHurtByMob() != null) {
-                return false;
-            } else if (!Fox.this.canMove()) {
-                return false;
-            } else if (Fox.this.getRandom().nextInt(reducedTickDelay(10)) != 0) {
-                return false;
+            } else if (Fox.this.getTarget() == null && Fox.this.getLastHurtByMob() == null) {
+                if (!Fox.this.canMove()) {
+                    return false;
+                } else if (Fox.this.getRandom().nextInt(reducedTickDelay(10)) != 0) {
+                    return false;
+                } else {
+                    List<ItemEntity> list = Fox.this.level().getEntitiesOfClass(ItemEntity.class, Fox.this.getBoundingBox().inflate(8.0D, 8.0D, 8.0D), Fox.ALLOWED_ITEMS);
+
+                    return !list.isEmpty() && Fox.this.getItemBySlot(EquipmentSlot.MAINHAND).isEmpty();
+                }
             } else {
-                List<ItemEntity> list = Fox.this.level()
-                    .getEntitiesOfClass(ItemEntity.class, Fox.this.getBoundingBox().inflate(8.0, 8.0, 8.0), Fox.ALLOWED_ITEMS);
-                return !list.isEmpty() && Fox.this.getItemBySlot(EquipmentSlot.MAINHAND).isEmpty();
+                return false;
             }
         }
 
         @Override
         public void tick() {
-            List<ItemEntity> list = Fox.this.level().getEntitiesOfClass(ItemEntity.class, Fox.this.getBoundingBox().inflate(8.0, 8.0, 8.0), Fox.ALLOWED_ITEMS);
-            ItemStack itemStack = Fox.this.getItemBySlot(EquipmentSlot.MAINHAND);
-            if (itemStack.isEmpty() && !list.isEmpty()) {
-                Fox.this.getNavigation().moveTo(list.get(0), 1.2F);
+            List<ItemEntity> list = Fox.this.level().getEntitiesOfClass(ItemEntity.class, Fox.this.getBoundingBox().inflate(8.0D, 8.0D, 8.0D), Fox.ALLOWED_ITEMS);
+            ItemStack itemstack = Fox.this.getItemBySlot(EquipmentSlot.MAINHAND);
+
+            if (itemstack.isEmpty() && !list.isEmpty()) {
+                Fox.this.getNavigation().moveTo((Entity) list.get(0), 1.2000000476837158D);
             }
+
         }
 
         @Override
         public void start() {
-            List<ItemEntity> list = Fox.this.level().getEntitiesOfClass(ItemEntity.class, Fox.this.getBoundingBox().inflate(8.0, 8.0, 8.0), Fox.ALLOWED_ITEMS);
+            List<ItemEntity> list = Fox.this.level().getEntitiesOfClass(ItemEntity.class, Fox.this.getBoundingBox().inflate(8.0D, 8.0D, 8.0D), Fox.ALLOWED_ITEMS);
+
             if (!list.isEmpty()) {
-                Fox.this.getNavigation().moveTo(list.get(0), 1.2F);
+                Fox.this.getNavigation().moveTo((Entity) list.get(0), 1.2000000476837158D);
             }
+
         }
     }
 
-    class FoxStrollThroughVillageGoal extends StrollThroughVillageGoal {
-        public FoxStrollThroughVillageGoal(final int unused, final int searchRange) {
-            super(Fox.this, searchRange);
-        }
+    private class FoxLookAtPlayerGoal extends LookAtPlayerGoal {
 
-        @Override
-        public void start() {
-            Fox.this.clearStates();
-            super.start();
+        public FoxLookAtPlayerGoal(final Mob mob, final Class targetType, final float range) {
+            super(mob, targetType, range);
         }
 
         @Override
         public boolean canUse() {
-            return super.canUse() && this.canFoxMove();
+            return super.canUse() && !Fox.this.isFaceplanted() && !Fox.this.isInterested();
         }
 
         @Override
         public boolean canContinueToUse() {
-            return super.canContinueToUse() && this.canFoxMove();
-        }
-
-        private boolean canFoxMove() {
-            return !Fox.this.isSleeping() && !Fox.this.isSitting() && !Fox.this.isDefending() && Fox.this.getTarget() == null;
+            return super.canContinueToUse() && !Fox.this.isFaceplanted() && !Fox.this.isInterested();
         }
     }
 
-    class PerchAndSearchGoal extends Fox.FoxBehaviorGoal {
+    private class PerchAndSearchGoal extends Fox.FoxBehaviorGoal {
+
         private double relX;
         private double relZ;
         private int lookTime;
         private int looksRemaining;
 
         public PerchAndSearchGoal() {
+            super();
             this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
         }
 
         @Override
         public boolean canUse() {
-            return Fox.this.getLastHurtByMob() == null
-                && Fox.this.getRandom().nextFloat() < 0.02F
-                && !Fox.this.isSleeping()
-                && Fox.this.getTarget() == null
-                && Fox.this.getNavigation().isDone()
-                && !this.alertable()
-                && !Fox.this.isPouncing()
-                && !Fox.this.isCrouching();
+            return Fox.this.getLastHurtByMob() == null && Fox.this.getRandom().nextFloat() < 0.02F && !Fox.this.isSleeping() && Fox.this.getTarget() == null && Fox.this.getNavigation().isDone() && !this.alertable() && !Fox.this.isPouncing() && !Fox.this.isCrouching();
         }
 
         @Override
@@ -1310,179 +1459,92 @@
 
         @Override
         public void tick() {
-            this.lookTime--;
+            --this.lookTime;
             if (this.lookTime <= 0) {
-                this.looksRemaining--;
+                --this.looksRemaining;
                 this.resetLook();
             }
 
-            Fox.this.getLookControl()
-                .setLookAt(
-                    Fox.this.getX() + this.relX,
-                    Fox.this.getEyeY(),
-                    Fox.this.getZ() + this.relZ,
-                    (float)Fox.this.getMaxHeadYRot(),
-                    (float)Fox.this.getMaxHeadXRot()
-                );
+            Fox.this.getLookControl().setLookAt(Fox.this.getX() + this.relX, Fox.this.getEyeY(), Fox.this.getZ() + this.relZ, (float) Fox.this.getMaxHeadYRot(), (float) Fox.this.getMaxHeadXRot());
         }
 
         private void resetLook() {
-            double d = (Math.PI * 2) * Fox.this.getRandom().nextDouble();
-            this.relX = Math.cos(d);
-            this.relZ = Math.sin(d);
+            double d0 = 6.283185307179586D * Fox.this.getRandom().nextDouble();
+
+            this.relX = Math.cos(d0);
+            this.relZ = Math.sin(d0);
             this.lookTime = this.adjustedTickDelay(80 + Fox.this.getRandom().nextInt(20));
         }
     }
 
-    class SeekShelterGoal extends FleeSunGoal {
-        private int interval = reducedTickDelay(100);
-
-        public SeekShelterGoal(final double speed) {
-            super(Fox.this, speed);
-        }
-
-        @Override
-        public boolean canUse() {
-            if (!Fox.this.isSleeping() && this.mob.getTarget() == null) {
-                if (Fox.this.level().isThundering() && Fox.this.level().canSeeSky(this.mob.blockPosition())) {
-                    return this.setWantedPos();
-                } else if (this.interval > 0) {
-                    this.interval--;
-                    return false;
-                } else {
-                    this.interval = 100;
-                    BlockPos blockPos = this.mob.blockPosition();
-                    return Fox.this.level().isDay()
-                        && Fox.this.level().canSeeSky(blockPos)
-                        && !((ServerLevel)Fox.this.level()).isVillage(blockPos)
-                        && this.setWantedPos();
-                }
-            } else {
-                return false;
-            }
-        }
-
-        @Override
-        public void start() {
-            Fox.this.clearStates();
-            super.start();
-        }
-    }
+    private class DefendTrustedTargetGoal extends NearestAttackableTargetGoal<LivingEntity> {
 
-    class SleepGoal extends Fox.FoxBehaviorGoal {
-        private static final int WAIT_TIME_BEFORE_SLEEP = reducedTickDelay(140);
-        private int countdown = Fox.this.random.nextInt(WAIT_TIME_BEFORE_SLEEP);
+        @Nullable
+        private LivingEntity trustedLastHurtBy;
+        @Nullable
+        private LivingEntity trustedLastHurt;
+        private int timestamp;
 
-        public SleepGoal() {
-            this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK, Goal.Flag.JUMP));
+        public DefendTrustedTargetGoal(final Class oclass, final boolean flag, final boolean flag1, @Nullable final Predicate<LivingEntity> predicate) { // CraftBukkit - decompile error
+            super(Fox.this, oclass, 10, flag, flag1, predicate);
         }
 
         @Override
         public boolean canUse() {
-            return Fox.this.xxa == 0.0F && Fox.this.yya == 0.0F && Fox.this.zza == 0.0F && (this.canSleep() || Fox.this.isSleeping());
-        }
-
-        @Override
-        public boolean canContinueToUse() {
-            return this.canSleep();
-        }
-
-        private boolean canSleep() {
-            if (this.countdown > 0) {
-                this.countdown--;
+            if (this.randomInterval > 0 && this.mob.getRandom().nextInt(this.randomInterval) != 0) {
                 return false;
             } else {
-                return Fox.this.level().isDay() && this.hasShelter() && !this.alertable() && !Fox.this.isInPowderSnow;
-            }
-        }
+                Iterator iterator = Fox.this.getTrustedUUIDs().iterator();
 
-        @Override
-        public void stop() {
-            this.countdown = Fox.this.random.nextInt(WAIT_TIME_BEFORE_SLEEP);
-            Fox.this.clearStates();
-        }
+                while (iterator.hasNext()) {
+                    UUID uuid = (UUID) iterator.next();
 
-        @Override
-        public void start() {
-            Fox.this.setSitting(false);
-            Fox.this.setIsCrouching(false);
-            Fox.this.setIsInterested(false);
-            Fox.this.setJumping(false);
-            Fox.this.setSleeping(true);
-            Fox.this.getNavigation().stop();
-            Fox.this.getMoveControl().setWantedPosition(Fox.this.getX(), Fox.this.getY(), Fox.this.getZ(), 0.0);
-        }
-    }
+                    if (uuid != null && Fox.this.level() instanceof ServerLevel) {
+                        Entity entity = ((ServerLevel) Fox.this.level()).getEntity(uuid);
 
-    class StalkPreyGoal extends Goal {
-        public StalkPreyGoal() {
-            this.setFlags(EnumSet.of(Goal.Flag.MOVE, Goal.Flag.LOOK));
-        }
+                        if (entity instanceof LivingEntity) {
+                            LivingEntity entityliving = (LivingEntity) entity;
+
+                            this.trustedLastHurt = entityliving;
+                            this.trustedLastHurtBy = entityliving.getLastHurtByMob();
+                            int i = entityliving.getLastHurtByMobTimestamp();
+
+                            return i != this.timestamp && this.canAttack(this.trustedLastHurtBy, this.targetConditions);
+                        }
+                    }
+                }
 
-        @Override
-        public boolean canUse() {
-            if (Fox.this.isSleeping()) {
                 return false;
-            } else {
-                LivingEntity livingEntity = Fox.this.getTarget();
-                return livingEntity != null
-                    && livingEntity.isAlive()
-                    && Fox.STALKABLE_PREY.test(livingEntity)
-                    && Fox.this.distanceToSqr(livingEntity) > 36.0
-                    && !Fox.this.isCrouching()
-                    && !Fox.this.isInterested()
-                    && !Fox.this.jumping;
             }
         }
 
         @Override
         public void start() {
-            Fox.this.setSitting(false);
-            Fox.this.setFaceplanted(false);
-        }
-
-        @Override
-        public void stop() {
-            LivingEntity livingEntity = Fox.this.getTarget();
-            if (livingEntity != null && Fox.isPathClear(Fox.this, livingEntity)) {
-                Fox.this.setIsInterested(true);
-                Fox.this.setIsCrouching(true);
-                Fox.this.getNavigation().stop();
-                Fox.this.getLookControl().setLookAt(livingEntity, (float)Fox.this.getMaxHeadYRot(), (float)Fox.this.getMaxHeadXRot());
-            } else {
-                Fox.this.setIsInterested(false);
-                Fox.this.setIsCrouching(false);
+            this.setTarget(this.trustedLastHurtBy);
+            this.target = this.trustedLastHurtBy;
+            if (this.trustedLastHurt != null) {
+                this.timestamp = this.trustedLastHurt.getLastHurtByMobTimestamp();
             }
-        }
 
-        @Override
-        public void tick() {
-            LivingEntity livingEntity = Fox.this.getTarget();
-            if (livingEntity != null) {
-                Fox.this.getLookControl().setLookAt(livingEntity, (float)Fox.this.getMaxHeadYRot(), (float)Fox.this.getMaxHeadXRot());
-                if (Fox.this.distanceToSqr(livingEntity) <= 36.0) {
-                    Fox.this.setIsInterested(true);
-                    Fox.this.setIsCrouching(true);
-                    Fox.this.getNavigation().stop();
-                } else {
-                    Fox.this.getNavigation().moveTo(livingEntity, 1.5);
-                }
-            }
+            Fox.this.playSound(SoundEvents.FOX_AGGRO, 1.0F, 1.0F);
+            Fox.this.setDefending(true);
+            Fox.this.wakeUp();
+            super.start();
         }
     }
 
     public static enum Type implements StringRepresentable {
-        RED(0, "red"),
-        SNOW(1, "snow");
+
+        RED(0, "red"), SNOW(1, "snow");
 
         public static final StringRepresentable.EnumCodec<Fox.Type> CODEC = StringRepresentable.fromEnum(Fox.Type::values);
         private static final IntFunction<Fox.Type> BY_ID = ByIdMap.continuous(Fox.Type::getId, values(), ByIdMap.OutOfBoundsStrategy.ZERO);
         private final int id;
         private final String name;
 
-        private Type(final int id, final String key) {
-            this.id = id;
-            this.name = key;
+        private Type(final int i, final String s) {
+            this.id = i;
+            this.name = s;
         }
 
         @Override
@@ -1495,15 +1557,51 @@
         }
 
         public static Fox.Type byName(String name) {
-            return CODEC.byName(name, RED);
+            return (Fox.Type) Fox.Type.CODEC.byName(name, Fox.Type.RED);
         }
 
         public static Fox.Type byId(int id) {
-            return BY_ID.apply(id);
+            return (Fox.Type) Fox.Type.BY_ID.apply(id);
         }
 
         public static Fox.Type byBiome(Holder<Biome> biome) {
-            return biome.is(BiomeTags.SPAWNS_SNOW_FOXES) ? SNOW : RED;
+            return biome.is(BiomeTags.SPAWNS_SNOW_FOXES) ? Fox.Type.SNOW : Fox.Type.RED;
+        }
+    }
+
+    public static class FoxGroupData extends AgeableMob.AgeableMobGroupData {
+
+        public final Fox.Type type;
+
+        public FoxGroupData(Fox.Type type) {
+            super(false);
+            this.type = type;
+        }
+    }
+
+    private abstract class FoxBehaviorGoal extends Goal {
+
+        private final TargetingConditions alertableTargeting = TargetingConditions.forCombat().range(12.0D).ignoreLineOfSight().selector(Fox.this.new FoxAlertableEntitiesSelector());
+
+        FoxBehaviorGoal() {}
+
+        protected boolean hasShelter() {
+            BlockPos blockposition = BlockPos.containing(Fox.this.getX(), Fox.this.getBoundingBox().maxY, Fox.this.getZ());
+
+            return !Fox.this.level().canSeeSky(blockposition) && Fox.this.getWalkTargetValue(blockposition) >= 0.0F;
+        }
+
+        protected boolean alertable() {
+            return !Fox.this.level().getNearbyEntities(LivingEntity.class, this.alertableTargeting, Fox.this, Fox.this.getBoundingBox().inflate(12.0D, 6.0D, 12.0D)).isEmpty();
+        }
+    }
+
+    public class FoxAlertableEntitiesSelector implements Predicate<LivingEntity> {
+
+        public FoxAlertableEntitiesSelector() {}
+
+        public boolean test(LivingEntity entityliving) {
+            return entityliving instanceof Fox ? false : (!(entityliving instanceof Chicken) && !(entityliving instanceof Rabbit) && !(entityliving instanceof Monster) ? (entityliving instanceof TamableAnimal ? !((TamableAnimal) entityliving).isTame() : (entityliving instanceof Player && (entityliving.isSpectator() || ((Player) entityliving).isCreative()) ? false : (Fox.this.trusts(entityliving.getUUID()) ? false : !entityliving.isSleeping() && !entityliving.isDiscrete()))) : true);
         }
     }
 }
