--- a/net/minecraft/world/entity/animal/horse/AbstractHorse.java
+++ b/net/minecraft/world/entity/animal/horse/AbstractHorse.java
@@ -1,5 +1,7 @@
 package net.minecraft.world.entity.animal.horse;
 
+import com.google.common.collect.UnmodifiableIterator;
+import java.util.Iterator;
 import java.util.UUID;
 import java.util.function.DoubleSupplier;
 import java.util.function.IntUnaryOperator;
@@ -9,8 +11,8 @@
 import net.minecraft.core.BlockPos;
 import net.minecraft.core.Direction;
 import net.minecraft.core.Holder;
-import net.minecraft.core.particles.ParticleOptions;
 import net.minecraft.core.particles.ParticleTypes;
+import net.minecraft.core.particles.SimpleParticleType;
 import net.minecraft.nbt.CompoundTag;
 import net.minecraft.network.syncher.EntityDataAccessor;
 import net.minecraft.network.syncher.EntityDataSerializers;
@@ -77,24 +79,47 @@
 import net.minecraft.world.phys.Vec3;
 import net.minecraft.world.ticks.ContainerSingleItem;
 
+// CraftBukkit start
+import java.util.Arrays;
+import java.util.List;
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.event.entity.EntityRegainHealthEvent;
+import org.bukkit.inventory.InventoryHolder;
+// CraftBukkit end
+
 public abstract class AbstractHorse extends Animal implements ContainerListener, HasCustomInventoryScreen, OwnableEntity, PlayerRideableJumping, Saddleable {
+
     public static final int EQUIPMENT_SLOT_OFFSET = 400;
     public static final int CHEST_SLOT_OFFSET = 499;
     public static final int INVENTORY_SLOT_OFFSET = 500;
-    public static final double BREEDING_CROSS_FACTOR = 0.15;
-    private static final float MIN_MOVEMENT_SPEED = (float)generateSpeed(() -> 0.0);
-    private static final float MAX_MOVEMENT_SPEED = (float)generateSpeed(() -> 1.0);
-    private static final float MIN_JUMP_STRENGTH = (float)generateJumpStrength(() -> 0.0);
-    private static final float MAX_JUMP_STRENGTH = (float)generateJumpStrength(() -> 1.0);
-    private static final float MIN_HEALTH = generateMaxHealth(max -> 0);
-    private static final float MAX_HEALTH = generateMaxHealth(max -> max - 1);
+    public static final double BREEDING_CROSS_FACTOR = 0.15D;
+    private static final float MIN_MOVEMENT_SPEED = (float) AbstractHorse.generateSpeed(() -> {
+        return 0.0D;
+    });
+    private static final float MAX_MOVEMENT_SPEED = (float) AbstractHorse.generateSpeed(() -> {
+        return 1.0D;
+    });
+    private static final float MIN_JUMP_STRENGTH = (float) AbstractHorse.generateJumpStrength(() -> {
+        return 0.0D;
+    });
+    private static final float MAX_JUMP_STRENGTH = (float) AbstractHorse.generateJumpStrength(() -> {
+        return 1.0D;
+    });
+    private static final float MIN_HEALTH = AbstractHorse.generateMaxHealth((i) -> {
+        return 0;
+    });
+    private static final float MAX_HEALTH = AbstractHorse.generateMaxHealth((i) -> {
+        return i - 1;
+    });
     private static final float BACKWARDS_MOVE_SPEED_FACTOR = 0.25F;
     private static final float SIDEWAYS_MOVE_SPEED_FACTOR = 0.5F;
-    private static final Predicate<LivingEntity> PARENT_HORSE_SELECTOR = entity -> entity instanceof AbstractHorse && ((AbstractHorse)entity).isBred();
-    private static final TargetingConditions MOMMY_TARGETING = TargetingConditions.forNonCombat()
-        .range(16.0)
-        .ignoreLineOfSight()
-        .selector(PARENT_HORSE_SELECTOR);
+    private static final Predicate<LivingEntity> PARENT_HORSE_SELECTOR = (entityliving) -> {
+        return entityliving instanceof AbstractHorse && ((AbstractHorse) entityliving).isBred();
+    };
+    private static final TargetingConditions MOMMY_TARGETING = TargetingConditions.forNonCombat().range(16.0D).ignoreLineOfSight().selector(AbstractHorse.PARENT_HORSE_SELECTOR);
     private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(AbstractHorse.class, EntityDataSerializers.BYTE);
     private static final int FLAG_TAME = 2;
     private static final int FLAG_SADDLE = 4;
@@ -136,14 +161,59 @@
         }
 
         @Override
-        public void setChanged() {
-        }
+        public void setChanged() {}
 
         @Override
         public boolean stillValid(Player player) {
-            return player.getVehicle() == AbstractHorse.this || player.canInteractWithEntity(AbstractHorse.this, 4.0);
+            return player.getVehicle() == AbstractHorse.this || player.canInteractWithEntity((Entity) AbstractHorse.this, 4.0D);
         }
+
+        // CraftBukkit start - add fields and methods
+        public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
+        private int maxStack = MAX_STACK;
+
+        @Override
+        public List<ItemStack> getContents() {
+            return Arrays.asList(this.getTheItem());
+        }
+
+        @Override
+        public void onOpen(CraftHumanEntity who) {
+            this.transaction.add(who);
+        }
+
+        @Override
+        public void onClose(CraftHumanEntity who) {
+            this.transaction.remove(who);
+        }
+
+        @Override
+        public List<HumanEntity> getViewers() {
+            return this.transaction;
+        }
+
+        @Override
+        public int getMaxStackSize() {
+            return this.maxStack;
+        }
+
+        @Override
+        public void setMaxStackSize(int size) {
+            this.maxStack = size;
+        }
+
+        @Override
+        public InventoryHolder getOwner() {
+            return (org.bukkit.entity.AbstractHorse) AbstractHorse.this.getBukkitEntity();
+        }
+
+        @Override
+        public Location getLocation() {
+            return AbstractHorse.this.getBukkitEntity().getLocation();
+        }
+        // CraftBukkit end
     };
+    public int maxDomestication = 100; // CraftBukkit - store max domestication value
 
     protected AbstractHorse(EntityType<? extends AbstractHorse> type, Level world) {
         super(type, world);
@@ -152,11 +222,11 @@
 
     @Override
     protected void registerGoals() {
-        this.goalSelector.addGoal(1, new PanicGoal(this, 1.2));
-        this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2));
-        this.goalSelector.addGoal(2, new BreedGoal(this, 1.0, AbstractHorse.class));
-        this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.0));
-        this.goalSelector.addGoal(6, new WaterAvoidingRandomStrollGoal(this, 0.7));
+        this.goalSelector.addGoal(1, new PanicGoal(this, 1.2D));
+        this.goalSelector.addGoal(1, new RunAroundLikeCrazyGoal(this, 1.2D));
+        this.goalSelector.addGoal(2, new BreedGoal(this, 1.0D, AbstractHorse.class));
+        this.goalSelector.addGoal(4, new FollowParentGoal(this, 1.0D));
+        this.goalSelector.addGoal(6, new WaterAvoidingRandomStrollGoal(this, 0.7D));
         this.goalSelector.addGoal(7, new LookAtPlayerGoal(this, Player.class, 6.0F));
         this.goalSelector.addGoal(8, new RandomLookAroundGoal(this));
         if (this.canPerformRearing()) {
@@ -168,26 +238,30 @@
 
     protected void addBehaviourGoals() {
         this.goalSelector.addGoal(0, new FloatGoal(this));
-        this.goalSelector.addGoal(3, new TemptGoal(this, 1.25, stack -> stack.is(ItemTags.HORSE_TEMPT_ITEMS), false));
+        this.goalSelector.addGoal(3, new TemptGoal(this, 1.25D, (itemstack) -> {
+            return itemstack.is(ItemTags.HORSE_TEMPT_ITEMS);
+        }, false));
     }
 
     @Override
     protected void defineSynchedData(SynchedEntityData.Builder builder) {
         super.defineSynchedData(builder);
-        builder.define(DATA_ID_FLAGS, (byte)0);
+        builder.define(AbstractHorse.DATA_ID_FLAGS, (byte) 0);
     }
 
     protected boolean getFlag(int bitmask) {
-        return (this.entityData.get(DATA_ID_FLAGS) & bitmask) != 0;
+        return ((Byte) this.entityData.get(AbstractHorse.DATA_ID_FLAGS) & bitmask) != 0;
     }
 
     protected void setFlag(int bitmask, boolean flag) {
-        byte b = this.entityData.get(DATA_ID_FLAGS);
+        byte b0 = (Byte) this.entityData.get(AbstractHorse.DATA_ID_FLAGS);
+
         if (flag) {
-            this.entityData.set(DATA_ID_FLAGS, (byte)(b | bitmask));
+            this.entityData.set(AbstractHorse.DATA_ID_FLAGS, (byte) (b0 | bitmask));
         } else {
-            this.entityData.set(DATA_ID_FLAGS, (byte)(b & ~bitmask));
+            this.entityData.set(AbstractHorse.DATA_ID_FLAGS, (byte) (b0 & ~bitmask));
         }
+
     }
 
     public boolean isTamed() {
@@ -221,6 +295,7 @@
         if (leashLength > 6.0F && this.isEating()) {
             this.setEating(false);
         }
+
     }
 
     public boolean isEating() {
@@ -246,7 +321,13 @@
 
     @Override
     public void equipSaddle(@Nullable SoundSource sound) {
-        this.inventory.setItem(0, new ItemStack(Items.SADDLE));
+        // Paper start - Fix saddles losing nbt data - MC-191591
+        this.equipSaddle(sound, null);
+    }
+    @Override
+    public void equipSaddle(@Nullable SoundSource sound, @Nullable ItemStack stack) {
+        this.inventory.setItem(0, stack != null ? stack : new ItemStack(Items.SADDLE));
+        // Paper end
     }
 
     public void equipBodyArmor(Player player, ItemStack stack) {
@@ -254,6 +335,7 @@
             this.setBodyArmorItem(stack.copyWithCount(1));
             stack.consume(1, player);
         }
+
     }
 
     @Override
@@ -270,34 +352,27 @@
     }
 
     public int modifyTemper(int difference) {
-        int i = Mth.clamp(this.getTemper() + difference, 0, this.getMaxTemper());
-        this.setTemper(i);
-        return i;
+        int j = Mth.clamp(this.getTemper() + difference, 0, this.getMaxTemper());
+
+        this.setTemper(j);
+        return j;
     }
 
     @Override
-    public boolean isPushable() {
+    public boolean isCollidable(boolean ignoreClimbing) { // Paper - Climbing should not bypass cramming gamerule
         return !this.isVehicle();
     }
 
     private void eating() {
         this.openMouth();
         if (!this.isSilent()) {
-            SoundEvent soundEvent = this.getEatingSound();
-            if (soundEvent != null) {
-                this.level()
-                    .playSound(
-                        null,
-                        this.getX(),
-                        this.getY(),
-                        this.getZ(),
-                        soundEvent,
-                        this.getSoundSource(),
-                        1.0F,
-                        1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F
-                    );
+            SoundEvent soundeffect = this.getEatingSound();
+
+            if (soundeffect != null) {
+                this.level().playSound((Player) null, this.getX(), this.getY(), this.getZ(), soundeffect, this.getSoundSource(), 1.0F, 1.0F + (this.random.nextFloat() - this.random.nextFloat()) * 0.2F);
             }
         }
+
     }
 
     @Override
@@ -307,13 +382,18 @@
         }
 
         int i = this.calculateFallDamage(fallDistance, damageMultiplier);
+
         if (i <= 0) {
             return false;
         } else {
-            this.hurt(damageSource, (float)i);
+            this.hurt(damageSource, (float) i);
             if (this.isVehicle()) {
-                for (Entity entity : this.getIndirectPassengers()) {
-                    entity.hurt(damageSource, (float)i);
+                Iterator iterator = this.getIndirectPassengers().iterator();
+
+                while (iterator.hasNext()) {
+                    Entity entity = (Entity) iterator.next();
+
+                    entity.hurt(damageSource, (float) i);
                 }
             }
 
@@ -327,16 +407,18 @@
     }
 
     public void createInventory() {
-        SimpleContainer simpleContainer = this.inventory;
-        this.inventory = new SimpleContainer(this.getInventorySize());
-        if (simpleContainer != null) {
-            simpleContainer.removeListener(this);
-            int i = Math.min(simpleContainer.getContainerSize(), this.inventory.getContainerSize());
+        SimpleContainer inventorysubcontainer = this.inventory;
 
-            for (int j = 0; j < i; j++) {
-                ItemStack itemStack = simpleContainer.getItem(j);
-                if (!itemStack.isEmpty()) {
-                    this.inventory.setItem(j, itemStack.copy());
+        this.inventory = new SimpleContainer(this.getInventorySize(), (org.bukkit.entity.AbstractHorse) this.getBukkitEntity()); // CraftBukkit
+        if (inventorysubcontainer != null) {
+            inventorysubcontainer.removeListener(this);
+            int i = Math.min(inventorysubcontainer.getContainerSize(), this.inventory.getContainerSize());
+
+            for (int j = 0; j < i; ++j) {
+                ItemStack itemstack = inventorysubcontainer.getItem(j);
+
+                if (!itemstack.isEmpty()) {
+                    this.inventory.setItem(j, itemstack.copy());
                 }
             }
         }
@@ -353,21 +435,24 @@
 
     @Override
     public void containerChanged(Container sender) {
-        boolean bl = this.isSaddled();
+        boolean flag = this.isSaddled();
+
         this.syncSaddleToClients();
-        if (this.tickCount > 20 && !bl && this.isSaddled()) {
+        if (this.tickCount > 20 && !flag && this.isSaddled()) {
             this.playSound(this.getSaddleSoundEvent(), 0.5F, 1.0F);
         }
+
     }
 
     @Override
     public boolean hurt(DamageSource source, float amount) {
-        boolean bl = super.hurt(source, amount);
-        if (bl && this.random.nextInt(3) == 0) {
+        boolean flag = super.hurt(source, amount);
+
+        if (flag && this.random.nextInt(3) == 0) {
             this.standIfPossible();
         }
 
-        return bl;
+        return flag;
     }
 
     protected boolean canPerformRearing() {
@@ -387,33 +472,31 @@
     @Override
     protected void playStepSound(BlockPos pos, BlockState state) {
         if (!state.liquid()) {
-            BlockState blockState = this.level().getBlockState(pos.above());
-            SoundType soundType = state.getSoundType();
-            if (blockState.is(Blocks.SNOW)) {
-                soundType = blockState.getSoundType();
+            BlockState iblockdata1 = this.level().getBlockState(pos.above());
+            SoundType soundeffecttype = state.getSoundType();
+
+            if (iblockdata1.is(Blocks.SNOW)) {
+                soundeffecttype = iblockdata1.getSoundType();
             }
 
             if (this.isVehicle() && this.canGallop) {
-                this.gallopSoundCounter++;
+                ++this.gallopSoundCounter;
                 if (this.gallopSoundCounter > 5 && this.gallopSoundCounter % 3 == 0) {
-                    this.playGallopSound(soundType);
+                    this.playGallopSound(soundeffecttype);
                 } else if (this.gallopSoundCounter <= 5) {
-                    this.playSound(SoundEvents.HORSE_STEP_WOOD, soundType.getVolume() * 0.15F, soundType.getPitch());
+                    this.playSound(SoundEvents.HORSE_STEP_WOOD, soundeffecttype.getVolume() * 0.15F, soundeffecttype.getPitch());
                 }
-            } else if (this.isWoodSoundType(soundType)) {
-                this.playSound(SoundEvents.HORSE_STEP_WOOD, soundType.getVolume() * 0.15F, soundType.getPitch());
+            } else if (this.isWoodSoundType(soundeffecttype)) {
+                this.playSound(SoundEvents.HORSE_STEP_WOOD, soundeffecttype.getVolume() * 0.15F, soundeffecttype.getPitch());
             } else {
-                this.playSound(SoundEvents.HORSE_STEP, soundType.getVolume() * 0.15F, soundType.getPitch());
+                this.playSound(SoundEvents.HORSE_STEP, soundeffecttype.getVolume() * 0.15F, soundeffecttype.getPitch());
             }
+
         }
     }
 
     private boolean isWoodSoundType(SoundType soundGroup) {
-        return soundGroup == SoundType.WOOD
-            || soundGroup == SoundType.NETHER_WOOD
-            || soundGroup == SoundType.STEM
-            || soundGroup == SoundType.CHERRY_WOOD
-            || soundGroup == SoundType.BAMBOO_WOOD;
+        return soundGroup == SoundType.WOOD || soundGroup == SoundType.NETHER_WOOD || soundGroup == SoundType.STEM || soundGroup == SoundType.CHERRY_WOOD || soundGroup == SoundType.BAMBOO_WOOD;
     }
 
     protected void playGallopSound(SoundType group) {
@@ -421,13 +504,7 @@
     }
 
     public static AttributeSupplier.Builder createBaseHorseAttributes() {
-        return Mob.createMobAttributes()
-            .add(Attributes.JUMP_STRENGTH, 0.7)
-            .add(Attributes.MAX_HEALTH, 53.0)
-            .add(Attributes.MOVEMENT_SPEED, 0.225F)
-            .add(Attributes.STEP_HEIGHT, 1.0)
-            .add(Attributes.SAFE_FALL_DISTANCE, 6.0)
-            .add(Attributes.FALL_DAMAGE_MULTIPLIER, 0.5);
+        return Mob.createMobAttributes().add(Attributes.JUMP_STRENGTH, 0.7D).add(Attributes.MAX_HEALTH, 53.0D).add(Attributes.MOVEMENT_SPEED, 0.22499999403953552D).add(Attributes.STEP_HEIGHT, 1.0D).add(Attributes.SAFE_FALL_DISTANCE, 6.0D).add(Attributes.FALL_DAMAGE_MULTIPLIER, 0.5D);
     }
 
     @Override
@@ -436,7 +513,7 @@
     }
 
     public int getMaxTemper() {
-        return 100;
+        return this.maxDomestication; // CraftBukkit - return stored max domestication instead of 100
     }
 
     @Override
@@ -451,86 +528,85 @@
 
     @Override
     public void openCustomInventoryScreen(Player player) {
-        if (!this.level().isClientSide && (!this.isVehicle() || this.hasPassenger(player)) && this.isTamed()) {
+        if (!this.level().isClientSide && (!this.isVehicle() || this.hasPassenger((Entity) player)) && this.isTamed()) {
             player.openHorseInventory(this, this.inventory);
         }
+
     }
 
     public InteractionResult fedFood(Player player, ItemStack stack) {
-        boolean bl = this.handleEating(player, stack);
-        if (bl) {
+        boolean flag = this.handleEating(player, stack);
+
+        if (flag) {
             stack.consume(1, player);
         }
 
-        if (this.level().isClientSide) {
-            return InteractionResult.CONSUME;
-        } else {
-            return bl ? InteractionResult.SUCCESS : InteractionResult.PASS;
-        }
+        return this.level().isClientSide ? InteractionResult.CONSUME : (flag ? InteractionResult.SUCCESS : InteractionResult.PASS);
     }
 
     protected boolean handleEating(Player player, ItemStack item) {
-        boolean bl = false;
+        boolean flag = false;
         float f = 0.0F;
-        int i = 0;
-        int j = 0;
+        short short0 = 0;
+        byte b0 = 0;
+
         if (item.is(Items.WHEAT)) {
             f = 2.0F;
-            i = 20;
-            j = 3;
+            short0 = 20;
+            b0 = 3;
         } else if (item.is(Items.SUGAR)) {
             f = 1.0F;
-            i = 30;
-            j = 3;
+            short0 = 30;
+            b0 = 3;
         } else if (item.is(Blocks.HAY_BLOCK.asItem())) {
             f = 20.0F;
-            i = 180;
+            short0 = 180;
         } else if (item.is(Items.APPLE)) {
             f = 3.0F;
-            i = 60;
-            j = 3;
+            short0 = 60;
+            b0 = 3;
         } else if (item.is(Items.GOLDEN_CARROT)) {
             f = 4.0F;
-            i = 60;
-            j = 5;
+            short0 = 60;
+            b0 = 5;
             if (!this.level().isClientSide && this.isTamed() && this.getAge() == 0 && !this.isInLove()) {
-                bl = true;
-                this.setInLove(player);
+                flag = true;
+                this.setInLove(player, item.copy()); // Paper - Fix EntityBreedEvent copying
             }
         } else if (item.is(Items.GOLDEN_APPLE) || item.is(Items.ENCHANTED_GOLDEN_APPLE)) {
             f = 10.0F;
-            i = 240;
-            j = 10;
+            short0 = 240;
+            b0 = 10;
             if (!this.level().isClientSide && this.isTamed() && this.getAge() == 0 && !this.isInLove()) {
-                bl = true;
-                this.setInLove(player);
+                flag = true;
+                this.setInLove(player, item.copy()); // Paper - Fix EntityBreedEvent copying
             }
         }
 
         if (this.getHealth() < this.getMaxHealth() && f > 0.0F) {
-            this.heal(f);
-            bl = true;
+            this.heal(f, EntityRegainHealthEvent.RegainReason.EATING); // CraftBukkit
+            flag = true;
         }
 
-        if (this.isBaby() && i > 0) {
-            this.level().addParticle(ParticleTypes.HAPPY_VILLAGER, this.getRandomX(1.0), this.getRandomY() + 0.5, this.getRandomZ(1.0), 0.0, 0.0, 0.0);
+        if (this.isBaby() && short0 > 0) {
+            this.level().addParticle(ParticleTypes.HAPPY_VILLAGER, this.getRandomX(1.0D), this.getRandomY() + 0.5D, this.getRandomZ(1.0D), 0.0D, 0.0D, 0.0D);
             if (!this.level().isClientSide) {
-                this.ageUp(i);
-                bl = true;
+                this.ageUp(short0);
+                flag = true;
             }
         }
 
-        if (j > 0 && (bl || !this.isTamed()) && this.getTemper() < this.getMaxTemper() && !this.level().isClientSide) {
-            this.modifyTemper(j);
-            bl = true;
+        if (b0 > 0 && (flag || !this.isTamed()) && this.getTemper() < this.getMaxTemper() && !this.level().isClientSide) {
+            this.modifyTemper(b0);
+            flag = true;
         }
 
-        if (bl) {
+        if (flag) {
             this.eating();
             this.gameEvent(GameEvent.EAT);
         }
 
-        return bl;
+        return flag;
     }
 
     protected void doPlayerRide(Player player) {
@@ -541,6 +617,7 @@
             player.setXRot(this.getXRot());
             player.startRiding(this);
         }
+
     }
 
     @Override
@@ -561,12 +638,14 @@
     protected void dropEquipment() {
         super.dropEquipment();
         if (this.inventory != null) {
-            for (int i = 0; i < this.inventory.getContainerSize(); i++) {
-                ItemStack itemStack = this.inventory.getItem(i);
-                if (!itemStack.isEmpty() && !EnchantmentHelper.hasVanishingCurse(itemStack)) {
-                    this.spawnAtLocation(itemStack);
+            for (int i = 0; i < this.inventory.getContainerSize(); ++i) {
+                ItemStack itemstack = this.inventory.getItem(i);
+
+                if (!itemstack.isEmpty() && !EnchantmentHelper.hasVanishingCurse(itemstack)) {
+                    this.spawnAtLocation(itemstack);
                 }
             }
+
         }
     }
 
@@ -579,14 +658,11 @@
         super.aiStep();
         if (!this.level().isClientSide && this.isAlive()) {
             if (this.random.nextInt(900) == 0 && this.deathTime == 0) {
-                this.heal(1.0F);
+                this.heal(1.0F, EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit
             }
 
             if (this.canEatGrass()) {
-                if (!this.isEating()
-                    && !this.isVehicle()
-                    && this.random.nextInt(300) == 0
-                    && this.level().getBlockState(this.blockPosition().below()).is(Blocks.GRASS_BLOCK)) {
+                if (!this.isEating() && !this.isVehicle() && this.random.nextInt(300) == 0 && this.level().getBlockState(this.blockPosition().below()).is(Blocks.GRASS_BLOCK)) {
                     this.setEating(true);
                 }
 
@@ -602,12 +678,13 @@
 
     protected void followMommy() {
         if (this.isBred() && this.isBaby() && !this.isEating()) {
-            LivingEntity livingEntity = this.level()
-                .getNearestEntity(AbstractHorse.class, MOMMY_TARGETING, this, this.getX(), this.getY(), this.getZ(), this.getBoundingBox().inflate(16.0));
-            if (livingEntity != null && this.distanceToSqr(livingEntity) > 4.0) {
-                this.navigation.createPath(livingEntity, 0);
+            LivingEntity entityliving = this.level().getNearestEntity(AbstractHorse.class, AbstractHorse.MOMMY_TARGETING, this, this.getX(), this.getY(), this.getZ(), this.getBoundingBox().inflate(16.0D));
+
+            if (entityliving != null && this.distanceToSqr((Entity) entityliving) > 4.0D) {
+                this.navigation.createPath((Entity) entityliving, 0);
             }
         }
+
     }
 
     public boolean canEatGrass() {
@@ -632,7 +709,7 @@
         }
 
         if (this.sprintCounter > 0) {
-            this.sprintCounter++;
+            ++this.sprintCounter;
             if (this.sprintCounter > 300) {
                 this.sprintCounter = 0;
             }
@@ -640,12 +717,12 @@
 
         this.eatAnimO = this.eatAnim;
         if (this.isEating()) {
-            this.eatAnim = this.eatAnim + (1.0F - this.eatAnim) * 0.4F + 0.05F;
+            this.eatAnim += (1.0F - this.eatAnim) * 0.4F + 0.05F;
             if (this.eatAnim > 1.0F) {
                 this.eatAnim = 1.0F;
             }
         } else {
-            this.eatAnim = this.eatAnim + ((0.0F - this.eatAnim) * 0.4F - 0.05F);
+            this.eatAnim += (0.0F - this.eatAnim) * 0.4F - 0.05F;
             if (this.eatAnim < 0.0F) {
                 this.eatAnim = 0.0F;
             }
@@ -655,13 +732,13 @@
         if (this.isStanding()) {
             this.eatAnim = 0.0F;
             this.eatAnimO = this.eatAnim;
-            this.standAnim = this.standAnim + (1.0F - this.standAnim) * 0.4F + 0.05F;
+            this.standAnim += (1.0F - this.standAnim) * 0.4F + 0.05F;
             if (this.standAnim > 1.0F) {
                 this.standAnim = 1.0F;
             }
         } else {
             this.allowStandSliding = false;
-            this.standAnim = this.standAnim + ((0.8F * this.standAnim * this.standAnim * this.standAnim - this.standAnim) * 0.6F - 0.05F);
+            this.standAnim += (0.8F * this.standAnim * this.standAnim * this.standAnim - this.standAnim) * 0.6F - 0.05F;
             if (this.standAnim < 0.0F) {
                 this.standAnim = 0.0F;
             }
@@ -669,41 +746,55 @@
 
         this.mouthAnimO = this.mouthAnim;
         if (this.getFlag(64)) {
-            this.mouthAnim = this.mouthAnim + (1.0F - this.mouthAnim) * 0.7F + 0.05F;
+            this.mouthAnim += (1.0F - this.mouthAnim) * 0.7F + 0.05F;
             if (this.mouthAnim > 1.0F) {
                 this.mouthAnim = 1.0F;
             }
         } else {
-            this.mouthAnim = this.mouthAnim + ((0.0F - this.mouthAnim) * 0.7F - 0.05F);
+            this.mouthAnim += (0.0F - this.mouthAnim) * 0.7F - 0.05F;
             if (this.mouthAnim < 0.0F) {
                 this.mouthAnim = 0.0F;
             }
         }
+
     }
 
+    // Paper start - Horse API
+    public void setMouthOpen(boolean open) {
+        this.setFlag(FLAG_OPEN_MOUTH, open);
+    }
+    public boolean isMouthOpen() {
+        return this.getFlag(FLAG_OPEN_MOUTH);
+    }
+    // Paper end - Horse API
+
     @Override
     public InteractionResult mobInteract(Player player, InteractionHand hand) {
-        if (this.isVehicle() || this.isBaby()) {
-            return super.mobInteract(player, hand);
-        } else if (this.isTamed() && player.isSecondaryUseActive()) {
-            this.openCustomInventoryScreen(player);
-            return InteractionResult.sidedSuccess(this.level().isClientSide);
-        } else {
-            ItemStack itemStack = player.getItemInHand(hand);
-            if (!itemStack.isEmpty()) {
-                InteractionResult interactionResult = itemStack.interactLivingEntity(player, this, hand);
-                if (interactionResult.consumesAction()) {
-                    return interactionResult;
-                }
+        if (!this.isVehicle() && !this.isBaby()) {
+            if (this.isTamed() && player.isSecondaryUseActive()) {
+                this.openCustomInventoryScreen(player);
+                return InteractionResult.sidedSuccess(this.level().isClientSide);
+            } else {
+                ItemStack itemstack = player.getItemInHand(hand);
 
-                if (this.canWearBodyArmor() && this.isBodyArmorItem(itemStack) && !this.isWearingBodyArmor()) {
-                    this.equipBodyArmor(player, itemStack);
-                    return InteractionResult.sidedSuccess(this.level().isClientSide);
+                if (!itemstack.isEmpty()) {
+                    InteractionResult enuminteractionresult = itemstack.interactLivingEntity(player, this, hand);
+
+                    if (enuminteractionresult.consumesAction()) {
+                        return enuminteractionresult;
+                    }
+
+                    if (this.canWearBodyArmor() && this.isBodyArmorItem(itemstack) && !this.isWearingBodyArmor()) {
+                        this.equipBodyArmor(player, itemstack);
+                        return InteractionResult.sidedSuccess(this.level().isClientSide);
+                    }
                 }
-            }
 
-            this.doPlayerRide(player);
-            return InteractionResult.sidedSuccess(this.level().isClientSide);
+                this.doPlayerRide(player);
+                return InteractionResult.sidedSuccess(this.level().isClientSide);
+            }
+        } else {
+            return super.mobInteract(player, hand);
         }
     }
 
@@ -712,12 +803,18 @@
             this.mouthCounter = 1;
             this.setFlag(64, true);
         }
+
     }
 
     public void setEating(boolean eatingGrass) {
         this.setFlag(16, eatingGrass);
     }
 
+    // Paper start - Horse API
+    public void setForceStanding(boolean standing) {
+        this.setFlag(FLAG_STANDING, standing);
+    }
+    // Paper end - Horse API
     public void setStanding(boolean angry) {
         if (angry) {
             this.setEating(false);
@@ -736,6 +833,7 @@
             this.standCounter = 1;
             this.setStanding(true);
         }
+
     }
 
     public void makeMad() {
@@ -743,27 +841,29 @@
             this.standIfPossible();
             this.makeSound(this.getAngrySound());
         }
+
     }
 
     public boolean tameWithName(Player player) {
         this.setOwnerUUID(player.getUUID());
         this.setTamed(true);
         if (player instanceof ServerPlayer) {
-            CriteriaTriggers.TAME_ANIMAL.trigger((ServerPlayer)player, this);
+            CriteriaTriggers.TAME_ANIMAL.trigger((ServerPlayer) player, (Animal) this);
         }
 
-        this.level().broadcastEntityEvent(this, (byte)7);
+        this.level().broadcastEntityEvent(this, (byte) 7);
         return true;
     }
 
     @Override
     protected void tickRidden(Player controllingPlayer, Vec3 movementInput) {
         super.tickRidden(controllingPlayer, movementInput);
-        Vec2 vec2 = this.getRiddenRotation(controllingPlayer);
-        this.setRot(vec2.y, vec2.x);
+        Vec2 vec2f = this.getRiddenRotation(controllingPlayer);
+
+        this.setRot(vec2f.y, vec2f.x);
         this.yRotO = this.yBodyRot = this.yHeadRot = this.getYRot();
         if (this.isControlledByLocalInstance()) {
-            if (movementInput.z <= 0.0) {
+            if (movementInput.z <= 0.0D) {
                 this.gallopSoundCounter = 0;
             }
 
@@ -776,6 +876,7 @@
                 this.playerJumpPendingScale = 0.0F;
             }
         }
+
     }
 
     protected Vec2 getRiddenRotation(LivingEntity controllingPassenger) {
@@ -788,31 +889,35 @@
             return Vec3.ZERO;
         } else {
             float f = controllingPlayer.xxa * 0.5F;
-            float g = controllingPlayer.zza;
-            if (g <= 0.0F) {
-                g *= 0.25F;
+            float f1 = controllingPlayer.zza;
+
+            if (f1 <= 0.0F) {
+                f1 *= 0.25F;
             }
 
-            return new Vec3((double)f, 0.0, (double)g);
+            return new Vec3((double) f, 0.0D, (double) f1);
         }
     }
 
     @Override
     protected float getRiddenSpeed(Player controllingPlayer) {
-        return (float)this.getAttributeValue(Attributes.MOVEMENT_SPEED);
+        return (float) this.getAttributeValue(Attributes.MOVEMENT_SPEED);
     }
 
     protected void executeRidersJump(float strength, Vec3 movementInput) {
-        double d = (double)this.getJumpPower(strength);
-        Vec3 vec3 = this.getDeltaMovement();
-        this.setDeltaMovement(vec3.x, d, vec3.z);
+        double d0 = (double) this.getJumpPower(strength);
+        Vec3 vec3d1 = this.getDeltaMovement();
+
+        this.setDeltaMovement(vec3d1.x, d0, vec3d1.z);
         this.setIsJumping(true);
         this.hasImpulse = true;
-        if (movementInput.z > 0.0) {
-            float f = Mth.sin(this.getYRot() * (float) (Math.PI / 180.0));
-            float g = Mth.cos(this.getYRot() * (float) (Math.PI / 180.0));
-            this.setDeltaMovement(this.getDeltaMovement().add((double)(-0.4F * f * strength), 0.0, (double)(0.4F * g * strength)));
+        if (movementInput.z > 0.0D) {
+            float f1 = Mth.sin(this.getYRot() * 0.017453292F);
+            float f2 = Mth.cos(this.getYRot() * 0.017453292F);
+
+            this.setDeltaMovement(this.getDeltaMovement().add((double) (-0.4F * f1 * strength), 0.0D, (double) (0.4F * f2 * strength)));
         }
+
     }
 
     protected void playJumpSound() {
@@ -829,10 +934,12 @@
         if (this.getOwnerUUID() != null) {
             nbt.putUUID("Owner", this.getOwnerUUID());
         }
+        nbt.putInt("Bukkit.MaxDomestication", this.maxDomestication); // CraftBukkit
 
         if (!this.inventory.getItem(0).isEmpty()) {
             nbt.put("SaddleItem", this.inventory.getItem(0).save(this.registryAccess()));
         }
+
     }
 
     @Override
@@ -842,22 +949,30 @@
         this.setBred(nbt.getBoolean("Bred"));
         this.setTemper(nbt.getInt("Temper"));
         this.setTamed(nbt.getBoolean("Tame"));
-        UUID uUID;
+        UUID uuid;
+
         if (nbt.hasUUID("Owner")) {
-            uUID = nbt.getUUID("Owner");
+            uuid = nbt.getUUID("Owner");
         } else {
-            String string = nbt.getString("Owner");
-            uUID = OldUsersConverter.convertMobOwnerIfNecessary(this.getServer(), string);
+            String s = nbt.getString("Owner");
+
+            uuid = OldUsersConverter.convertMobOwnerIfNecessary(this.getServer(), s);
         }
 
-        if (uUID != null) {
-            this.setOwnerUUID(uUID);
+        if (uuid != null) {
+            this.setOwnerUUID(uuid);
         }
+        // CraftBukkit start
+        if (nbt.contains("Bukkit.MaxDomestication")) {
+            this.maxDomestication = nbt.getInt("Bukkit.MaxDomestication");
+        }
+        // CraftBukkit end
 
         if (nbt.contains("SaddleItem", 10)) {
-            ItemStack itemStack = ItemStack.parse(this.registryAccess(), nbt.getCompound("SaddleItem")).orElse(ItemStack.EMPTY);
-            if (itemStack.is(Items.SADDLE)) {
-                this.inventory.setItem(0, itemStack);
+            ItemStack itemstack = (ItemStack) ItemStack.parse(this.registryAccess(), nbt.getCompound("SaddleItem")).orElse(ItemStack.EMPTY);
+
+            if (itemstack.is(Items.SADDLE)) {
+                this.inventory.setItem(0, itemstack);
             }
         }
 
@@ -880,14 +995,15 @@
     }
 
     protected void setOffspringAttributes(AgeableMob other, AbstractHorse child) {
-        this.setOffspringAttribute(other, child, Attributes.MAX_HEALTH, (double)MIN_HEALTH, (double)MAX_HEALTH);
-        this.setOffspringAttribute(other, child, Attributes.JUMP_STRENGTH, (double)MIN_JUMP_STRENGTH, (double)MAX_JUMP_STRENGTH);
-        this.setOffspringAttribute(other, child, Attributes.MOVEMENT_SPEED, (double)MIN_MOVEMENT_SPEED, (double)MAX_MOVEMENT_SPEED);
+        this.setOffspringAttribute(other, child, Attributes.MAX_HEALTH, (double) AbstractHorse.MIN_HEALTH, (double) AbstractHorse.MAX_HEALTH);
+        this.setOffspringAttribute(other, child, Attributes.JUMP_STRENGTH, (double) AbstractHorse.MIN_JUMP_STRENGTH, (double) AbstractHorse.MAX_JUMP_STRENGTH);
+        this.setOffspringAttribute(other, child, Attributes.MOVEMENT_SPEED, (double) AbstractHorse.MIN_MOVEMENT_SPEED, (double) AbstractHorse.MAX_MOVEMENT_SPEED);
     }
 
     private void setOffspringAttribute(AgeableMob other, AbstractHorse child, Holder<Attribute> attribute, double min, double max) {
-        double d = createOffspringAttribute(this.getAttributeBaseValue(attribute), other.getAttributeBaseValue(attribute), min, max, this.random);
-        child.getAttribute(attribute).setBaseValue(d);
+        double d2 = AbstractHorse.createOffspringAttribute(this.getAttributeBaseValue(attribute), other.getAttributeBaseValue(attribute), min, max, this.random);
+
+        child.getAttribute(attribute).setBaseValue(d2);
     }
 
     static double createOffspringAttribute(double parentBase, double otherParentBase, double min, double max, RandomSource random) {
@@ -896,19 +1012,21 @@
         } else {
             parentBase = Mth.clamp(parentBase, min, max);
             otherParentBase = Mth.clamp(otherParentBase, min, max);
-            double d = 0.15 * (max - min);
-            double e = Math.abs(parentBase - otherParentBase) + d * 2.0;
-            double f = (parentBase + otherParentBase) / 2.0;
-            double g = (random.nextDouble() + random.nextDouble() + random.nextDouble()) / 3.0 - 0.5;
-            double h = f + e * g;
-            if (h > max) {
-                double i = h - max;
-                return max - i;
-            } else if (h < min) {
-                double j = min - h;
-                return min + j;
+            double d4 = 0.15D * (max - min);
+            double d5 = Math.abs(parentBase - otherParentBase) + d4 * 2.0D;
+            double d6 = (parentBase + otherParentBase) / 2.0D;
+            double d7 = (random.nextDouble() + random.nextDouble() + random.nextDouble()) / 3.0D - 0.5D;
+            double d8 = d6 + d5 * d7;
+            double d9;
+
+            if (d8 > max) {
+                d9 = d8 - max;
+                return max - d9;
+            } else if (d8 < min) {
+                d9 = min - d8;
+                return min + d9;
             } else {
-                return h;
+                return d8;
             }
         }
     }
@@ -938,8 +1056,9 @@
             if (strength >= 90) {
                 this.playerJumpPendingScale = 1.0F;
             } else {
-                this.playerJumpPendingScale = 0.4F + 0.4F * (float)strength / 90.0F;
+                this.playerJumpPendingScale = 0.4F + 0.4F * (float) strength / 90.0F;
             }
+
         }
     }
 
@@ -950,24 +1069,36 @@
 
     @Override
     public void handleStartJump(int height) {
+        // CraftBukkit start
+        float power;
+        if (height >= 90) {
+            power = 1.0F;
+        } else {
+            power = 0.4F + 0.4F * (float) height / 90.0F;
+        }
+        if (!CraftEventFactory.callHorseJumpEvent(this, power)) {
+            return;
+        }
+        // CraftBukkit end
         this.allowStandSliding = true;
         this.standIfPossible();
         this.playJumpSound();
     }
 
     @Override
-    public void handleStopJump() {
-    }
+    public void handleStopJump() {}
 
     protected void spawnTamingParticles(boolean positive) {
-        ParticleOptions particleOptions = positive ? ParticleTypes.HEART : ParticleTypes.SMOKE;
+        SimpleParticleType particletype = positive ? ParticleTypes.HEART : ParticleTypes.SMOKE;
 
-        for (int i = 0; i < 7; i++) {
-            double d = this.random.nextGaussian() * 0.02;
-            double e = this.random.nextGaussian() * 0.02;
-            double f = this.random.nextGaussian() * 0.02;
-            this.level().addParticle(particleOptions, this.getRandomX(1.0), this.getRandomY() + 0.5, this.getRandomZ(1.0), d, e, f);
+        for (int i = 0; i < 7; ++i) {
+            double d0 = this.random.nextGaussian() * 0.02D;
+            double d1 = this.random.nextGaussian() * 0.02D;
+            double d2 = this.random.nextGaussian() * 0.02D;
+
+            this.level().addParticle(particletype, this.getRandomX(1.0D), this.getRandomY() + 0.5D, this.getRandomZ(1.0D), d0, d1, d2);
         }
+
     }
 
     @Override
@@ -979,26 +1110,28 @@
         } else {
             super.handleEntityEvent(status);
         }
+
     }
 
     @Override
     protected void positionRider(Entity passenger, Entity.MoveFunction positionUpdater) {
         super.positionRider(passenger, positionUpdater);
         if (passenger instanceof LivingEntity) {
-            ((LivingEntity)passenger).yBodyRot = this.yBodyRot;
+            ((LivingEntity) passenger).yBodyRot = this.yBodyRot;
         }
+
     }
 
     protected static float generateMaxHealth(IntUnaryOperator randomIntGetter) {
-        return 15.0F + (float)randomIntGetter.applyAsInt(8) + (float)randomIntGetter.applyAsInt(9);
+        return 15.0F + (float) randomIntGetter.applyAsInt(8) + (float) randomIntGetter.applyAsInt(9);
     }
 
     protected static double generateJumpStrength(DoubleSupplier randomDoubleGetter) {
-        return 0.4F + randomDoubleGetter.getAsDouble() * 0.2 + randomDoubleGetter.getAsDouble() * 0.2 + randomDoubleGetter.getAsDouble() * 0.2;
+        return 0.4000000059604645D + randomDoubleGetter.getAsDouble() * 0.2D + randomDoubleGetter.getAsDouble() * 0.2D + randomDoubleGetter.getAsDouble() * 0.2D;
     }
 
     protected static double generateSpeed(DoubleSupplier randomDoubleGetter) {
-        return (0.45F + randomDoubleGetter.getAsDouble() * 0.3 + randomDoubleGetter.getAsDouble() * 0.3 + randomDoubleGetter.getAsDouble() * 0.3) * 0.25;
+        return (0.44999998807907104D + randomDoubleGetter.getAsDouble() * 0.3D + randomDoubleGetter.getAsDouble() * 0.3D + randomDoubleGetter.getAsDouble() * 0.3D) * 0.25D;
     }
 
     @Override
@@ -1008,8 +1141,9 @@
 
     @Override
     public SlotAccess getSlot(int mappedIndex) {
-        int i = mappedIndex - 400;
-        if (i == 0) {
+        int j = mappedIndex - 400;
+
+        if (j == 0) {
             return new SlotAccess() {
                 @Override
                 public ItemStack get() {
@@ -1028,8 +1162,9 @@
                 }
             };
         } else {
-            int j = mappedIndex - 500 + 1;
-            return j >= 1 && j < this.inventory.getContainerSize() ? SlotAccess.forContainer(this.inventory, j) : super.getSlot(mappedIndex);
+            int k = mappedIndex - 500 + 1;
+
+            return k >= 1 && k < this.inventory.getContainerSize() ? SlotAccess.forContainer(this.inventory, k) : super.getSlot(mappedIndex);
         }
     }
 
@@ -1037,9 +1172,12 @@
     @Override
     public LivingEntity getControllingPassenger() {
         if (this.isSaddled()) {
-            Entity var2 = this.getFirstPassenger();
-            if (var2 instanceof Player) {
-                return (Player)var2;
+            Entity entity = this.getFirstPassenger();
+
+            if (entity instanceof Player) {
+                Player entityhuman = (Player) entity;
+
+                return entityhuman;
             }
         }
 
@@ -1048,32 +1186,40 @@
 
     @Nullable
     private Vec3 getDismountLocationInDirection(Vec3 offset, LivingEntity passenger) {
-        double d = this.getX() + offset.x;
-        double e = this.getBoundingBox().minY;
-        double f = this.getZ() + offset.z;
-        BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
+        double d0 = this.getX() + offset.x;
+        double d1 = this.getBoundingBox().minY;
+        double d2 = this.getZ() + offset.z;
+        BlockPos.MutableBlockPos blockposition_mutableblockposition = new BlockPos.MutableBlockPos();
+        UnmodifiableIterator unmodifiableiterator = passenger.getDismountPoses().iterator();
 
-        for (Pose pose : passenger.getDismountPoses()) {
-            mutableBlockPos.set(d, e, f);
-            double g = this.getBoundingBox().maxY + 0.75;
+        while (unmodifiableiterator.hasNext()) {
+            Pose entitypose = (Pose) unmodifiableiterator.next();
 
-            do {
-                double h = this.level().getBlockFloorHeight(mutableBlockPos);
-                if ((double)mutableBlockPos.getY() + h > g) {
+            blockposition_mutableblockposition.set(d0, d1, d2);
+            double d3 = this.getBoundingBox().maxY + 0.75D;
+
+            while (true) {
+                double d4 = this.level().getBlockFloorHeight(blockposition_mutableblockposition);
+
+                if ((double) blockposition_mutableblockposition.getY() + d4 > d3) {
                     break;
                 }
 
-                if (DismountHelper.isBlockFloorValid(h)) {
-                    AABB aABB = passenger.getLocalBoundsForPose(pose);
-                    Vec3 vec3 = new Vec3(d, (double)mutableBlockPos.getY() + h, f);
-                    if (DismountHelper.canDismountTo(this.level(), passenger, aABB.move(vec3))) {
-                        passenger.setPose(pose);
-                        return vec3;
+                if (DismountHelper.isBlockFloorValid(d4)) {
+                    AABB axisalignedbb = passenger.getLocalBoundsForPose(entitypose);
+                    Vec3 vec3d1 = new Vec3(d0, (double) blockposition_mutableblockposition.getY() + d4, d2);
+
+                    if (DismountHelper.canDismountTo(this.level(), passenger, axisalignedbb.move(vec3d1))) {
+                        passenger.setPose(entitypose);
+                        return vec3d1;
                     }
                 }
 
-                mutableBlockPos.move(Direction.UP);
-            } while (!((double)mutableBlockPos.getY() < g));
+                blockposition_mutableblockposition.move(Direction.UP);
+                if ((double) blockposition_mutableblockposition.getY() >= d3) {
+                    break;
+                }
+            }
         }
 
         return null;
@@ -1081,23 +1227,20 @@
 
     @Override
     public Vec3 getDismountLocationForPassenger(LivingEntity passenger) {
-        Vec3 vec3 = getCollisionHorizontalEscapeVector(
-            (double)this.getBbWidth(), (double)passenger.getBbWidth(), this.getYRot() + (passenger.getMainArm() == HumanoidArm.RIGHT ? 90.0F : -90.0F)
-        );
-        Vec3 vec32 = this.getDismountLocationInDirection(vec3, passenger);
-        if (vec32 != null) {
-            return vec32;
+        Vec3 vec3d = getCollisionHorizontalEscapeVector((double) this.getBbWidth(), (double) passenger.getBbWidth(), this.getYRot() + (passenger.getMainArm() == HumanoidArm.RIGHT ? 90.0F : -90.0F));
+        Vec3 vec3d1 = this.getDismountLocationInDirection(vec3d, passenger);
+
+        if (vec3d1 != null) {
+            return vec3d1;
         } else {
-            Vec3 vec33 = getCollisionHorizontalEscapeVector(
-                (double)this.getBbWidth(), (double)passenger.getBbWidth(), this.getYRot() + (passenger.getMainArm() == HumanoidArm.LEFT ? 90.0F : -90.0F)
-            );
-            Vec3 vec34 = this.getDismountLocationInDirection(vec33, passenger);
-            return vec34 != null ? vec34 : this.position();
+            Vec3 vec3d2 = getCollisionHorizontalEscapeVector((double) this.getBbWidth(), (double) passenger.getBbWidth(), this.getYRot() + (passenger.getMainArm() == HumanoidArm.LEFT ? 90.0F : -90.0F));
+            Vec3 vec3d3 = this.getDismountLocationInDirection(vec3d2, passenger);
+
+            return vec3d3 != null ? vec3d3 : this.position();
         }
     }
 
-    protected void randomizeAttributes(RandomSource random) {
-    }
+    protected void randomizeAttributes(RandomSource random) {}
 
     @Nullable
     @Override
@@ -1107,7 +1250,7 @@
         }
 
         this.randomizeAttributes(world.getRandom());
-        return super.finalizeSpawn(world, difficulty, spawnReason, entityData);
+        return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData);
     }
 
     public boolean hasInventoryChanged(Container inventory) {
@@ -1120,11 +1263,7 @@
 
     @Override
     protected Vec3 getPassengerAttachmentPoint(Entity passenger, EntityDimensions dimensions, float scaleFactor) {
-        return super.getPassengerAttachmentPoint(passenger, dimensions, scaleFactor)
-            .add(
-                new Vec3(0.0, 0.15 * (double)this.standAnimO * (double)scaleFactor, -0.7 * (double)this.standAnimO * (double)scaleFactor)
-                    .yRot(-this.getYRot() * (float) (Math.PI / 180.0))
-            );
+        return super.getPassengerAttachmentPoint(passenger, dimensions, scaleFactor).add((new Vec3(0.0D, 0.15D * (double) this.standAnimO * (double) scaleFactor, -0.7D * (double) this.standAnimO * (double) scaleFactor)).yRot(-this.getYRot() * 0.017453292F));
     }
 
     public final Container getBodyArmorAccess() {
