--- a/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java
+++ b/net/minecraft/world/entity/animal/horse/EntityHorseAbstract.java
@@ -79,6 +79,18 @@
 import net.minecraft.world.phys.Vec3D;
 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.AbstractHorse;
+import org.bukkit.entity.HumanEntity;
+import org.bukkit.event.entity.EntityRegainHealthEvent;
+import org.bukkit.inventory.InventoryHolder;
+// CraftBukkit end
+
 public abstract class EntityHorseAbstract extends EntityAnimal implements IInventoryListener, HasCustomInventoryScreen, OwnableEntity, IJumpable, ISaddleable {
 
     public static final int EQUIPMENT_SLOT_OFFSET = 400;
@@ -167,7 +179,53 @@
         public boolean stillValid(EntityHuman entityhuman) {
             return entityhuman.getVehicle() == EntityHorseAbstract.this || entityhuman.canInteractWithEntity((Entity) EntityHorseAbstract.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) {
+            transaction.add(who);
+        }
+
+        @Override
+        public void onClose(CraftHumanEntity who) {
+            transaction.remove(who);
+        }
+
+        @Override
+        public List<HumanEntity> getViewers() {
+            return transaction;
+        }
+
+        @Override
+        public int getMaxStackSize() {
+            return maxStack;
+        }
+
+        @Override
+        public void setMaxStackSize(int size) {
+            maxStack = size;
+        }
+
+        @Override
+        public InventoryHolder getOwner() {
+            return (AbstractHorse) EntityHorseAbstract.this.getBukkitEntity();
+        }
+
+        @Override
+        public Location getLocation() {
+            return EntityHorseAbstract.this.getBukkitEntity().getLocation();
+        }
+        // CraftBukkit end
     };
+    public int maxDomestication = 100; // CraftBukkit - store max domestication value
 
     protected EntityHorseAbstract(EntityTypes<? extends EntityHorseAbstract> entitytypes, World world) {
         super(entitytypes, world);
@@ -366,7 +424,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());
@@ -470,7 +528,7 @@
     }
 
     public int getMaxTemper() {
-        return 100;
+        return this.maxDomestication; // CraftBukkit - return stored max domestication instead of 100
     }
 
     @Override
@@ -541,7 +599,7 @@
         }
 
         if (this.getHealth() < this.getMaxHealth() && f > 0.0F) {
-            this.heal(f);
+            this.heal(f, EntityRegainHealthEvent.RegainReason.EATING); // CraftBukkit
             flag = true;
         }
 
@@ -618,7 +676,7 @@
         if (world instanceof WorldServer worldserver) {
             if (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()) {
@@ -883,6 +941,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(this.registryAccess()));
@@ -910,6 +969,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) ItemStack.parse(this.registryAccess(), nbttagcompound.getCompound("SaddleItem")).orElse(ItemStack.EMPTY);
@@ -1012,6 +1076,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();
