--- 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.Optional;
 import java.util.UUID;
 import java.util.function.Predicate;
@@ -7,8 +9,8 @@
 import net.minecraft.advancements.CriteriaTriggers;
 import net.minecraft.core.BlockPos;
 import net.minecraft.core.Direction;
-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;
@@ -71,15 +73,17 @@
 import net.minecraft.world.level.gameevent.GameEvent;
 import net.minecraft.world.phys.AABB;
 import net.minecraft.world.phys.Vec3;
+import org.bukkit.event.entity.EntityRegainHealthEvent.RegainReason; // CraftBukkit
 
 public abstract class AbstractHorse extends Animal implements ContainerListener, HasCustomInventoryScreen, 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;
-    private static final Predicate<LivingEntity> PARENT_HORSE_SELECTOR = (entity) -> {
-        return entity instanceof AbstractHorse && ((AbstractHorse)entity).isBred();
+    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(PARENT_HORSE_SELECTOR);
+    private static final TargetingConditions MOMMY_TARGETING = TargetingConditions.forNonCombat().range(16.0D).ignoreLineOfSight().selector(AbstractHorse.PARENT_HORSE_SELECTOR);
     private static final Ingredient FOOD_ITEMS = Ingredient.of(Items.WHEAT, Items.SUGAR, Blocks.HAY_BLOCK.asItem(), Items.APPLE, Items.GOLDEN_CARROT, Items.GOLDEN_APPLE, Items.ENCHANTED_GOLDEN_APPLE);
     private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(AbstractHorse.class, EntityDataSerializers.BYTE);
     private static final EntityDataAccessor<Optional<UUID>> DATA_ID_OWNER_UUID = SynchedEntityData.defineId(AbstractHorse.class, EntityDataSerializers.OPTIONAL_UUID);
@@ -110,6 +114,7 @@
     private float mouthAnimO;
     protected boolean canGallop = true;
     protected int gallopSoundCounter;
+    public int maxDomestication = 100; // CraftBukkit - store max domestication value
 
     protected AbstractHorse(EntityType<? extends AbstractHorse> type, Level world) {
         super(type, world);
@@ -141,20 +146,21 @@
     @Override
     protected void defineSynchedData() {
         super.defineSynchedData();
-        this.entityData.define(DATA_ID_FLAGS, (byte)0);
-        this.entityData.define(DATA_ID_OWNER_UUID, Optional.empty());
+        this.entityData.define(AbstractHorse.DATA_ID_FLAGS, (byte) 0);
+        this.entityData.define(AbstractHorse.DATA_ID_OWNER_UUID, Optional.empty());
     }
 
     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));
         }
 
     }
@@ -165,11 +171,11 @@
 
     @Nullable
     public UUID getOwnerUUID() {
-        return this.entityData.get(DATA_ID_OWNER_UUID).orElse((UUID)null);
+        return (UUID) ((Optional) this.entityData.get(AbstractHorse.DATA_ID_OWNER_UUID)).orElse((Object) null);
     }
 
     public void setOwnerUUID(@Nullable UUID uuid) {
-        this.entityData.set(DATA_ID_OWNER_UUID, Optional.ofNullable(uuid));
+        this.entityData.set(AbstractHorse.DATA_ID_OWNER_UUID, Optional.ofNullable(uuid));
     }
 
     public boolean isJumping() {
@@ -217,7 +223,7 @@
     public void equipSaddle(@Nullable SoundSource sound) {
         this.inventory.setItem(0, new ItemStack(Items.SADDLE));
         if (sound != null) {
-            this.level.playSound((Player)null, this, this.getSaddleSoundEvent(), sound, 0.5F, 1.0F);
+            this.level.playSound((Player) null, (Entity) this, this.getSaddleSoundEvent(), sound, 0.5F, 1.0F);
         }
 
     }
@@ -246,22 +252,24 @@
     }
 
     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, (int) 0, this.getMaxTemper());
+
+        this.setTemper(j);
+        return j;
     }
 
     @Override
-    public boolean isPushable() {
+    public boolean isCollidable(boolean ignoreClimbing) { // Paper
         return !this.isVehicle();
     }
 
     private void eating() {
         this.openMouth();
         if (!this.isSilent()) {
-            SoundEvent soundEvent = this.getEatingSound();
-            if (soundEvent != null) {
-                this.level.playSound((Player)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);
             }
         }
 
@@ -274,13 +282,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);
                 }
             }
 
@@ -299,16 +312,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());
                 }
             }
         }
@@ -325,9 +340,10 @@
 
     @Override
     public void containerChanged(Container sender) {
-        boolean bl = this.isSaddled();
+        boolean flag = this.isSaddled();
+
         this.updateContainerEquipment();
-        if (this.tickCount > 20 && !bl && this.isSaddled()) {
+        if (this.tickCount > 20 && !flag && this.isSaddled()) {
             this.playSound(SoundEvents.HORSE_SADDLE, 0.5F, 1.0F);
         }
 
@@ -339,12 +355,13 @@
 
     @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() {
@@ -364,23 +381,24 @@
     @Override
     protected void playStepSound(BlockPos pos, BlockState state) {
         if (!state.getMaterial().isLiquid()) {
-            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;
                 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 (soundType == SoundType.WOOD) {
-                this.playSound(SoundEvents.HORSE_STEP_WOOD, soundType.getVolume() * 0.15F, soundType.getPitch());
+            } else if (soundeffecttype == SoundType.WOOD) {
+                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());
             }
 
         }
@@ -391,7 +409,7 @@
     }
 
     public static AttributeSupplier.Builder createBaseHorseAttributes() {
-        return Mob.createMobAttributes().add(Attributes.JUMP_STRENGTH).add(Attributes.MAX_HEALTH, 53.0D).add(Attributes.MOVEMENT_SPEED, (double)0.225F);
+        return Mob.createMobAttributes().add(Attributes.JUMP_STRENGTH).add(Attributes.MAX_HEALTH, 53.0D).add(Attributes.MOVEMENT_SPEED, 0.22499999403953552D);
     }
 
     @Override
@@ -400,7 +418,7 @@
     }
 
     public int getMaxTemper() {
-        return 100;
+        return this.maxDomestication; // CraftBukkit - return stored max domestication instead of 100
     }
 
     @Override
@@ -415,90 +433,88 @@
 
     @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);
+        boolean flag = this.handleEating(player, stack);
+
         if (!player.getAbilities().instabuild) {
             stack.shrink(1);
         }
 
-        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;
+                flag = true;
                 this.setInLove(player);
             }
         } 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;
+                flag = true;
                 this.setInLove(player);
             }
         }
 
         if (this.getHealth() < this.getMaxHealth() && f > 0.0F) {
-            this.heal(f);
-            bl = true;
+            this.heal(f, RegainReason.EATING); // CraftBukkit
+            flag = true;
         }
 
-        if (this.isBaby() && i > 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);
+                this.ageUp(short0);
             }
 
-            bl = true;
+            flag = true;
         }
 
-        if (j > 0 && (bl || !this.isTamed()) && this.getTemper() < this.getMaxTemper()) {
-            bl = true;
+        if (b0 > 0 && (flag || !this.isTamed()) && this.getTemper() < this.getMaxTemper()) {
+            flag = true;
             if (!this.level.isClientSide) {
-                this.modifyTemper(j);
+                this.modifyTemper(b0);
             }
         }
 
-        if (bl) {
+        if (flag) {
             this.eating();
             this.gameEvent(GameEvent.EAT);
         }
 
-        return bl;
+        return flag;
     }
 
     protected void doPlayerRide(Player player) {
@@ -519,7 +535,7 @@
 
     @Override
     public boolean isFood(ItemStack stack) {
-        return FOOD_ITEMS.test(stack);
+        return AbstractHorse.FOOD_ITEMS.test(stack);
     }
 
     private void moveTail() {
@@ -530,10 +546,11 @@
     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);
                 }
             }
 
@@ -549,7 +566,7 @@
         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, RegainReason.REGEN); // CraftBukkit
             }
 
             if (this.canEatGrass()) {
@@ -569,9 +586,10 @@
 
     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.0D));
-            if (livingEntity != null && this.distanceToSqr(livingEntity) > 4.0D) {
-                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);
             }
         }
 
@@ -649,6 +667,15 @@
 
     }
 
+    // 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()) {
@@ -656,15 +683,17 @@
                 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;
+                ItemStack itemstack = player.getItemInHand(hand);
+
+                if (!itemstack.isEmpty()) {
+                    InteractionResult enuminteractionresult = itemstack.interactLivingEntity(player, this, hand);
+
+                    if (enuminteractionresult.consumesAction()) {
+                        return enuminteractionresult;
                     }
 
-                    if (this.canWearArmor() && this.isArmor(itemStack) && !this.isWearingArmor()) {
-                        this.equipArmor(player, itemStack);
+                    if (this.canWearArmor() && this.isArmor(itemstack) && !this.isWearingArmor()) {
+                        this.equipArmor(player, itemstack);
                         return InteractionResult.sidedSuccess(this.level.isClientSide);
                     }
                 }
@@ -689,6 +718,11 @@
         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);
@@ -713,9 +747,10 @@
     public void makeMad() {
         if (!this.isStanding()) {
             this.standIfPossible();
-            SoundEvent soundEvent = this.getAngrySound();
-            if (soundEvent != null) {
-                this.playSound(soundEvent, this.getSoundVolume(), this.getVoicePitch());
+            SoundEvent soundeffect = this.getAngrySound();
+
+            if (soundeffect != null) {
+                this.playSound(soundeffect, this.getSoundVolume(), this.getVoicePitch());
             }
         }
 
@@ -725,42 +760,44 @@
         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
     public void travel(Vec3 movementInput) {
         if (this.isAlive()) {
-            LivingEntity livingEntity = this.getControllingPassenger();
-            if (this.isVehicle() && livingEntity != null && !this.mountIgnoresControllerInput(livingEntity)) {
-                this.setRot(livingEntity.getYRot(), livingEntity.getXRot() * 0.5F);
+            LivingEntity entityliving = this.getControllingPassenger();
+
+            if (this.isVehicle() && entityliving != null && !this.mountIgnoresControllerInput(entityliving)) {
+                this.setRot(entityliving.getYRot(), entityliving.getXRot() * 0.5F);
                 this.yRotO = this.yBodyRot = this.yHeadRot = this.getYRot();
-                float f = livingEntity.xxa * 0.5F;
-                float g = livingEntity.zza;
-                if (g <= 0.0F) {
-                    g *= 0.25F;
+                float f = entityliving.xxa * 0.5F;
+                float f1 = entityliving.zza;
+
+                if (f1 <= 0.0F) {
+                    f1 *= 0.25F;
                     this.gallopSoundCounter = 0;
                 }
 
                 if (this.onGround && this.playerJumpPendingScale == 0.0F && this.isStanding() && !this.allowStandSliding) {
                     f = 0.0F;
-                    g = 0.0F;
+                    f1 = 0.0F;
                 }
 
                 if (this.playerJumpPendingScale > 0.0F && !this.isJumping() && this.onGround) {
-                    this.executeRidersJump(this.playerJumpPendingScale, f, g);
+                    this.executeRidersJump(this.playerJumpPendingScale, f, f1);
                     this.playerJumpPendingScale = 0.0F;
                 }
 
                 this.flyingSpeed = this.getSpeed() * 0.1F;
                 if (this.isControlledByLocalInstance()) {
-                    this.setSpeed(this.getDrivenMovementSpeed(livingEntity));
-                    super.travel(new Vec3((double)f, movementInput.y, (double)g));
-                } else if (livingEntity instanceof Player) {
+                    this.setSpeed(this.getDrivenMovementSpeed(entityliving));
+                    super.travel(new Vec3((double) f, movementInput.y, (double) f1));
+                } else if (entityliving instanceof Player) {
                     this.setDeltaMovement(this.getX() - this.xOld, this.getY() - this.yOld, this.getZ() - this.zOld);
                 }
 
@@ -779,7 +816,7 @@
     }
 
     protected float getDrivenMovementSpeed(LivingEntity passenger) {
-        return (float)this.getAttributeValue(Attributes.MOVEMENT_SPEED);
+        return (float) this.getAttributeValue(Attributes.MOVEMENT_SPEED);
     }
 
     protected boolean mountIgnoresControllerInput(LivingEntity passenger) {
@@ -787,16 +824,18 @@
     }
 
     protected void executeRidersJump(float strength, float sidewaysSpeed, float forwardSpeed) {
-        double d = this.getCustomJump() * (double)strength * (double)this.getBlockJumpFactor();
-        double e = d + this.getJumpBoostPower();
-        Vec3 vec3 = this.getDeltaMovement();
-        this.setDeltaMovement(vec3.x, e, vec3.z);
+        double d0 = this.getCustomJump() * (double) strength * (double) this.getBlockJumpFactor();
+        double d1 = d0 + this.getJumpBoostPower();
+        Vec3 vec3d = this.getDeltaMovement();
+
+        this.setDeltaMovement(vec3d.x, d1, vec3d.z);
         this.setIsJumping(true);
         this.hasImpulse = true;
         if (forwardSpeed > 0.0F) {
-            float f = Mth.sin(this.getYRot() * ((float)Math.PI / 180F));
-            float g = Mth.cos(this.getYRot() * ((float)Math.PI / 180F));
-            this.setDeltaMovement(this.getDeltaMovement().add((double)(-0.4F * f * strength), 0.0D, (double)(0.4F * g * strength)));
+            float f3 = Mth.sin(this.getYRot() * 0.017453292F);
+            float f4 = Mth.cos(this.getYRot() * 0.017453292F);
+
+            this.setDeltaMovement(this.getDeltaMovement().add((double) (-0.4F * f3 * strength), 0.0D, (double) (0.4F * f4 * strength)));
         }
 
     }
@@ -815,6 +854,7 @@
         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(new CompoundTag()));
@@ -829,22 +869,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.of(nbt.getCompound("SaddleItem"));
-            if (itemStack.is(Items.SADDLE)) {
-                this.inventory.setItem(0, itemStack);
+            ItemStack itemstack = ItemStack.of(nbt.getCompound("SaddleItem"));
+
+            if (itemstack.is(Items.SADDLE)) {
+                this.inventory.setItem(0, itemstack);
             }
         }
 
@@ -867,12 +915,15 @@
     }
 
     protected void setOffspringAttributes(AgeableMob mate, AbstractHorse child) {
-        double d = this.getAttributeBaseValue(Attributes.MAX_HEALTH) + mate.getAttributeBaseValue(Attributes.MAX_HEALTH) + (double)this.generateRandomMaxHealth(this.random);
-        child.getAttribute(Attributes.MAX_HEALTH).setBaseValue(d / 3.0D);
-        double e = this.getAttributeBaseValue(Attributes.JUMP_STRENGTH) + mate.getAttributeBaseValue(Attributes.JUMP_STRENGTH) + this.generateRandomJumpStrength(this.random);
-        child.getAttribute(Attributes.JUMP_STRENGTH).setBaseValue(e / 3.0D);
-        double f = this.getAttributeBaseValue(Attributes.MOVEMENT_SPEED) + mate.getAttributeBaseValue(Attributes.MOVEMENT_SPEED) + this.generateRandomSpeed(this.random);
-        child.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(f / 3.0D);
+        double d0 = this.getAttributeBaseValue(Attributes.MAX_HEALTH) + mate.getAttributeBaseValue(Attributes.MAX_HEALTH) + (double) this.generateRandomMaxHealth(this.random);
+
+        child.getAttribute(Attributes.MAX_HEALTH).setBaseValue(d0 / 3.0D);
+        double d1 = this.getAttributeBaseValue(Attributes.JUMP_STRENGTH) + mate.getAttributeBaseValue(Attributes.JUMP_STRENGTH) + this.generateRandomJumpStrength(this.random);
+
+        child.getAttribute(Attributes.JUMP_STRENGTH).setBaseValue(d1 / 3.0D);
+        double d2 = this.getAttributeBaseValue(Attributes.MOVEMENT_SPEED) + mate.getAttributeBaseValue(Attributes.MOVEMENT_SPEED) + this.generateRandomSpeed(this.random);
+
+        child.getAttribute(Attributes.MOVEMENT_SPEED).setBaseValue(d2 / 3.0D);
     }
 
     public float getEatAnim(float tickDelta) {
@@ -900,7 +951,7 @@
             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;
             }
 
         }
@@ -913,23 +964,35 @@
 
     @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;
+        }
+        org.bukkit.event.entity.HorseJumpEvent event = org.bukkit.craftbukkit.v1_19_R2.event.CraftEventFactory.callHorseJumpEvent(this, power);
+        if (event.isCancelled()) {
+            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.02D;
-            double e = this.random.nextGaussian() * 0.02D;
-            double f = this.random.nextGaussian() * 0.02D;
-            this.level.addParticle(particleOptions, this.getRandomX(1.0D), this.getRandomY() + 0.5D, this.getRandomZ(1.0D), 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);
         }
 
     }
@@ -949,33 +1012,36 @@
     @Override
     public void positionRider(Entity passenger) {
         super.positionRider(passenger);
-        if (passenger instanceof Mob mob) {
-            this.yBodyRot = mob.yBodyRot;
+        if (passenger instanceof Mob) {
+            Mob entityinsentient = (Mob) passenger;
+
+            this.yBodyRot = entityinsentient.yBodyRot;
         }
 
         if (this.standAnimO > 0.0F) {
-            float f = Mth.sin(this.yBodyRot * ((float)Math.PI / 180F));
-            float g = Mth.cos(this.yBodyRot * ((float)Math.PI / 180F));
-            float h = 0.7F * this.standAnimO;
-            float i = 0.15F * this.standAnimO;
-            passenger.setPos(this.getX() + (double)(h * f), this.getY() + this.getPassengersRidingOffset() + passenger.getMyRidingOffset() + (double)i, this.getZ() - (double)(h * g));
+            float f = Mth.sin(this.yBodyRot * 0.017453292F);
+            float f1 = Mth.cos(this.yBodyRot * 0.017453292F);
+            float f2 = 0.7F * this.standAnimO;
+            float f3 = 0.15F * this.standAnimO;
+
+            passenger.setPos(this.getX() + (double) (f2 * f), this.getY() + this.getPassengersRidingOffset() + passenger.getMyRidingOffset() + (double) f3, this.getZ() - (double) (f2 * f1));
             if (passenger instanceof LivingEntity) {
-                ((LivingEntity)passenger).yBodyRot = this.yBodyRot;
+                ((LivingEntity) passenger).yBodyRot = this.yBodyRot;
             }
         }
 
     }
 
     protected float generateRandomMaxHealth(RandomSource random) {
-        return 15.0F + (float)random.nextInt(8) + (float)random.nextInt(9);
+        return 15.0F + (float) random.nextInt(8) + (float) random.nextInt(9);
     }
 
     protected double generateRandomJumpStrength(RandomSource random) {
-        return (double)0.4F + random.nextDouble() * 0.2D + random.nextDouble() * 0.2D + random.nextDouble() * 0.2D;
+        return 0.4000000059604645D + random.nextDouble() * 0.2D + random.nextDouble() * 0.2D + random.nextDouble() * 0.2D;
     }
 
     protected double generateRandomSpeed(RandomSource random) {
-        return ((double)0.45F + random.nextDouble() * 0.3D + random.nextDouble() * 0.3D + random.nextDouble() * 0.3D) * 0.25D;
+        return (0.44999998807907104D + random.nextDouble() * 0.3D + random.nextDouble() * 0.3D + random.nextDouble() * 0.3D) * 0.25D;
     }
 
     @Override
@@ -1022,36 +1088,41 @@
 
     @Override
     public SlotAccess getSlot(int mappedIndex) {
-        int i = mappedIndex - 400;
-        if (i >= 0 && i < 2 && i < this.inventory.getContainerSize()) {
-            if (i == 0) {
-                return this.createEquipmentSlotAccess(i, (stack) -> {
-                    return stack.isEmpty() || stack.is(Items.SADDLE);
+        int j = mappedIndex - 400;
+
+        if (j >= 0 && j < 2 && j < this.inventory.getContainerSize()) {
+            if (j == 0) {
+                return this.createEquipmentSlotAccess(j, (itemstack) -> {
+                    return itemstack.isEmpty() || itemstack.is(Items.SADDLE);
                 });
             }
 
-            if (i == 1) {
+            if (j == 1) {
                 if (!this.canWearArmor()) {
                     return SlotAccess.NULL;
                 }
 
-                return this.createEquipmentSlotAccess(i, (stack) -> {
-                    return stack.isEmpty() || this.isArmor(stack);
+                return this.createEquipmentSlotAccess(j, (itemstack) -> {
+                    return itemstack.isEmpty() || this.isArmor(itemstack);
                 });
             }
         }
 
-        int j = mappedIndex - 500 + 2;
-        return j >= 2 && j < this.inventory.getContainerSize() ? SlotAccess.forContainer(this.inventory, j) : super.getSlot(mappedIndex);
+        int k = mappedIndex - 500 + 2;
+
+        return k >= 2 && k < this.inventory.getContainerSize() ? SlotAccess.forContainer(this.inventory, k) : super.getSlot(mappedIndex);
     }
 
     @Nullable
     @Override
     public LivingEntity getControllingPassenger() {
         if (this.isSaddled()) {
-            Entity var2 = this.getFirstPassenger();
-            if (var2 instanceof LivingEntity) {
-                return (LivingEntity)var2;
+            Entity entity = this.getFirstPassenger();
+
+            if (entity instanceof LivingEntity) {
+                LivingEntity entityliving = (LivingEntity) entity;
+
+                return entityliving;
             }
         }
 
@@ -1060,32 +1131,37 @@
 
     @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.75D;
+        while (unmodifiableiterator.hasNext()) {
+            Pose entitypose = (Pose) unmodifiableiterator.next();
 
-            while(true) {
-                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);
-                if (!((double)mutableBlockPos.getY() < g)) {
+                blockposition_mutableblockposition.move(Direction.UP);
+                if ((double) blockposition_mutableblockposition.getY() >= d3) {
                     break;
                 }
             }
@@ -1096,19 +1172,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
@@ -1118,7 +1195,7 @@
         }
 
         this.randomizeAttributes(world.getRandom());
-        return super.finalizeSpawn(world, difficulty, spawnReason, entityData, entityNbt);
+        return super.finalizeSpawn(world, difficulty, spawnReason, (SpawnGroupData) entityData, entityNbt);
     }
 
     public boolean hasInventoryChanged(Container inventory) {
