--- a/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java
+++ b/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java
@@ -78,6 +78,12 @@
 import net.minecraft.world.phys.Vec2F;
 import net.minecraft.world.phys.Vec3D;
 
+// CraftBukkit start
+import org.bukkit.craftbukkit.event.CraftEventFactory;
+import org.bukkit.entity.AbstractHorse;
+import org.bukkit.event.entity.EntityRegainHealthEvent;
+// CraftBukkit end
+
 public abstract class EntityHorseAbstract extends EntityAnimal implements IInventoryListener, HasCustomInventoryScreen, OwnableEntity, IJumpable, ISaddleable {
 
     public static final int EQUIPMENT_SLOT_OFFSET = 400;
@@ -139,6 +145,7 @@
     protected int gallopSoundCounter;
     @Nullable
     private UUID owner;
+    public int maxDomestication = 100; // CraftBukkit - store max domestication value
 
     protected EntityHorseAbstract(EntityTypes<? extends EntityHorseAbstract> entitytypes, World world) {
         super(entitytypes, world);
@@ -334,7 +341,7 @@
     public void createInventory() {
         InventorySubcontainer inventorysubcontainer = this.inventory;
 
-        this.inventory = new InventorySubcontainer(this.getInventorySize());
+        this.inventory = new InventorySubcontainer(this.getInventorySize(), (AbstractHorse) this.getBukkitEntity()); // CraftBukkit
         if (inventorysubcontainer != null) {
             inventorysubcontainer.removeListener(this);
             int i = Math.min(inventorysubcontainer.getContainerSize(), this.inventory.getContainerSize());
@@ -442,7 +449,7 @@
     }
 
     public int getMaxTemper() {
-        return 100;
+        return this.maxDomestication; // CraftBukkit - return stored max domestication instead of 100
     }
 
     @Override
@@ -513,7 +520,7 @@
         }
 
         if (this.getHealth() < this.getMaxHealth() && f > 0.0F) {
-            this.heal(f);
+            this.heal(f, EntityRegainHealthEvent.RegainReason.EATING); // CraftBukkit
             flag = true;
         }
 
@@ -590,7 +597,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, EntityRegainHealthEvent.RegainReason.REGEN); // CraftBukkit
             }
 
             if (this.canEatGrass()) {
@@ -857,6 +864,7 @@
         if (this.getOwnerUUID() != null) {
             nbttagcompound.putUUID("Owner", this.getOwnerUUID());
         }
+        nbttagcompound.putInt("Bukkit.MaxDomestication", this.maxDomestication); // CraftBukkit
 
         if (!this.inventory.getItem(0).isEmpty()) {
             nbttagcompound.put("SaddleItem", this.inventory.getItem(0).save(new NBTTagCompound()));
@@ -884,6 +892,11 @@
         if (uuid != null) {
             this.setOwnerUUID(uuid);
         }
+        // CraftBukkit start
+        if (nbttagcompound.contains("Bukkit.MaxDomestication")) {
+            this.maxDomestication = nbttagcompound.getInt("Bukkit.MaxDomestication");
+        }
+        // CraftBukkit end
 
         if (nbttagcompound.contains("SaddleItem", 10)) {
             ItemStack itemstack = ItemStack.of(nbttagcompound.getCompound("SaddleItem"));
@@ -986,6 +999,17 @@
 
     @Override
     public void handleStartJump(int i) {
+        // CraftBukkit start
+        float power;
+        if (i >= 90) {
+            power = 1.0F;
+        } else {
+            power = 0.4F + 0.4F * (float) i / 90.0F;
+        }
+        if (!CraftEventFactory.callHorseJumpEvent(this, power)) {
+            return;
+        }
+        // CraftBukkit end
         this.allowStandSliding = true;
         this.standIfPossible();
         this.playJumpSound();
