--- a/net/minecraft/world/entity/PathfinderMob.java
+++ b/net/minecraft/world/entity/PathfinderMob.java
@@ -1,5 +1,6 @@
 package net.minecraft.world.entity;
 
+import java.util.Iterator;
 import net.minecraft.core.BlockPos;
 import net.minecraft.world.entity.ai.goal.Goal;
 import net.minecraft.world.entity.ai.goal.PanicGoal;
@@ -9,14 +10,21 @@
 import net.minecraft.world.level.LevelAccessor;
 import net.minecraft.world.level.LevelReader;
 import net.minecraft.world.phys.Vec3;
+// CraftBukkit start
+import org.bukkit.event.entity.EntityUnleashEvent;
+// CraftBukkit end
 
 public abstract class PathfinderMob extends Mob {
+
     protected static final float DEFAULT_WALK_TARGET_VALUE = 0.0F;
 
     protected PathfinderMob(EntityType<? extends PathfinderMob> type, Level world) {
         super(type, world);
     }
 
+    public org.bukkit.craftbukkit.entity.CraftCreature getBukkitCreature() { return (org.bukkit.craftbukkit.entity.CraftCreature) super.getBukkitEntity(); } // Paper
+    public BlockPos movingTarget = null; public BlockPos getMovingTarget() { return movingTarget; } // Paper
+
     public float getWalkTargetValue(BlockPos pos) {
         return this.getWalkTargetValue(pos, this.level());
     }
@@ -38,13 +46,19 @@
         if (this.brain.hasMemoryValue(MemoryModuleType.IS_PANICKING)) {
             return this.brain.getMemory(MemoryModuleType.IS_PANICKING).isPresent();
         } else {
-            for (WrappedGoal wrappedGoal : this.goalSelector.getAvailableGoals()) {
-                if (wrappedGoal.isRunning() && wrappedGoal.getGoal() instanceof PanicGoal) {
-                    return true;
+            Iterator iterator = this.goalSelector.getAvailableGoals().iterator();
+
+            WrappedGoal pathfindergoalwrapped;
+
+            do {
+                if (!iterator.hasNext()) {
+                    return false;
                 }
-            }
 
-            return false;
+                pathfindergoalwrapped = (WrappedGoal) iterator.next();
+            } while (!pathfindergoalwrapped.isRunning() || !(pathfindergoalwrapped.getGoal() instanceof PanicGoal));
+
+            return true;
         }
     }
 
@@ -52,36 +66,47 @@
     protected void tickLeash() {
         super.tickLeash();
         Entity entity = this.getLeashHolder();
+
         if (entity != null && entity.level() == this.level()) {
             this.restrictTo(entity.blockPosition(), 5);
             float f = this.distanceTo(entity);
-            if (this instanceof TamableAnimal && ((TamableAnimal)this).isInSittingPose()) {
-                if (f > 10.0F) {
-                    this.dropLeash(true, true);
+
+            if (this instanceof TamableAnimal && ((TamableAnimal) this).isInSittingPose()) {
+                if (f > entity.level().paperConfig().misc.maxLeashDistance) { // Paper - Configurable max leash distance
+                    // Paper start - Expand EntityUnleashEvent
+                    EntityUnleashEvent event = new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE, true);
+                    if (!event.callEvent()) return;
+                    this.dropLeash(true, event.isDropLeash());
+                    // Paper end - Expand EntityUnleashEvent
                 }
 
                 return;
             }
 
             this.onLeashDistance(f);
-            if (f > 10.0F) {
-                this.dropLeash(true, true);
+            if (f > entity.level().paperConfig().misc.maxLeashDistance) { // Paper - Configurable max leash distance
+                // Paper start - Expand EntityUnleashEvent
+                EntityUnleashEvent event = new EntityUnleashEvent(this.getBukkitEntity(), EntityUnleashEvent.UnleashReason.DISTANCE, true);
+                if (!event.callEvent()) return;
+                this.dropLeash(true, event.isDropLeash());
+                // Paper end - Expand EntityUnleashEvent
                 this.goalSelector.disableControlFlag(Goal.Flag.MOVE);
             } else if (f > 6.0F) {
-                double d = (entity.getX() - this.getX()) / (double)f;
-                double e = (entity.getY() - this.getY()) / (double)f;
-                double g = (entity.getZ() - this.getZ()) / (double)f;
-                this.setDeltaMovement(this.getDeltaMovement().add(Math.copySign(d * d * 0.4, d), Math.copySign(e * e * 0.4, e), Math.copySign(g * g * 0.4, g)));
+                double d0 = (entity.getX() - this.getX()) / (double) f;
+                double d1 = (entity.getY() - this.getY()) / (double) f;
+                double d2 = (entity.getZ() - this.getZ()) / (double) f;
+
+                this.setDeltaMovement(this.getDeltaMovement().add(Math.copySign(d0 * d0 * 0.4D, d0), Math.copySign(d1 * d1 * 0.4D, d1), Math.copySign(d2 * d2 * 0.4D, d2)));
                 this.checkSlowFallDistance();
             } else if (this.shouldStayCloseToLeashHolder() && !this.isPanicking()) {
                 this.goalSelector.enableControlFlag(Goal.Flag.MOVE);
-                float h = 2.0F;
-                Vec3 vec3 = new Vec3(entity.getX() - this.getX(), entity.getY() - this.getY(), entity.getZ() - this.getZ())
-                    .normalize()
-                    .scale((double)Math.max(f - 2.0F, 0.0F));
-                this.getNavigation().moveTo(this.getX() + vec3.x, this.getY() + vec3.y, this.getZ() + vec3.z, this.followLeashSpeed());
+                float f1 = 2.0F;
+                Vec3 vec3d = (new Vec3(entity.getX() - this.getX(), entity.getY() - this.getY(), entity.getZ() - this.getZ())).normalize().scale((double) Math.max(f - 2.0F, 0.0F));
+
+                this.getNavigation().moveTo(this.getX() + vec3d.x, this.getY() + vec3d.y, this.getZ() + vec3d.z, this.followLeashSpeed());
             }
         }
+
     }
 
     protected boolean shouldStayCloseToLeashHolder() {
@@ -89,9 +114,8 @@
     }
 
     protected double followLeashSpeed() {
-        return 1.0;
+        return 1.0D;
     }
 
-    protected void onLeashDistance(float leashLength) {
-    }
+    protected void onLeashDistance(float leashLength) {}
 }
