--- a/net/minecraft/world/SimpleContainer.java
+++ b/net/minecraft/world/SimpleContainer.java
@@ -1,6 +1,7 @@
 package net.minecraft.world;
 
 import com.google.common.collect.Lists;
+import java.util.Iterator;
 import java.util.List;
 import java.util.stream.Collectors;
 import javax.annotation.Nullable;
@@ -13,15 +14,96 @@
 import net.minecraft.world.item.Item;
 import net.minecraft.world.item.ItemStack;
 
+// CraftBukkit start
+import org.bukkit.Location;
+import org.bukkit.craftbukkit.entity.CraftHumanEntity;
+import org.bukkit.entity.HumanEntity;
+// CraftBukkit end
+
 public class SimpleContainer implements Container, StackedContentsCompatible {
+
     private final int size;
     public final NonNullList<ItemStack> items;
     @Nullable
     private List<ContainerListener> listeners;
 
+    // CraftBukkit start - add fields and methods
+    public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
+    private int maxStack = MAX_STACK;
+    protected @Nullable org.bukkit.inventory.InventoryHolder bukkitOwner; // Paper - annotation
+
+    public List<ItemStack> getContents() {
+        return this.items;
+    }
+
+    public void onOpen(CraftHumanEntity who) {
+        this.transaction.add(who);
+    }
+
+    public void onClose(CraftHumanEntity who) {
+        this.transaction.remove(who);
+    }
+
+    public List<HumanEntity> getViewers() {
+        return this.transaction;
+    }
+
+    @Override
+    public int getMaxStackSize() {
+        return this.maxStack;
+    }
+
+    public void setMaxStackSize(int i) {
+        this.maxStack = i;
+    }
+
+    public org.bukkit.inventory.InventoryHolder getOwner() {
+        // Paper start - Add missing InventoryHolders
+        if (this.bukkitOwner == null && this.bukkitOwnerCreator != null) {
+            this.bukkitOwner = this.bukkitOwnerCreator.get();
+        }
+        // Paper end - Add missing InventoryHolders
+        return this.bukkitOwner;
+    }
+
+    @Override
+    public Location getLocation() {
+        // Paper start - Fix inventories returning null Locations
+        // When the block inventory does not have a tile state that implements getLocation, e. g. composters
+        if (this.bukkitOwner instanceof org.bukkit.inventory.BlockInventoryHolder blockInventoryHolder) {
+            return blockInventoryHolder.getBlock().getLocation();
+        }
+        // When the bukkit owner is a bukkit entity, but does not implement Container itself, e. g. horses
+        if (this.bukkitOwner instanceof org.bukkit.entity.Entity entity) {
+            return entity.getLocation();
+        }
+        // Paper end - Fix inventories returning null Locations
+        return null;
+    }
+
+    public SimpleContainer(SimpleContainer original) {
+        this(original.size);
+        for (int slot = 0; slot < original.size; slot++) {
+            this.items.set(slot, original.items.get(slot).copy());
+        }
+    }
+
     public SimpleContainer(int size) {
-        this.size = size;
-        this.items = NonNullList.withSize(size, ItemStack.EMPTY);
+        this(size, null);
+    }
+    // Paper start - Add missing InventoryHolders
+    private @Nullable java.util.function.Supplier<? extends org.bukkit.inventory.InventoryHolder> bukkitOwnerCreator;
+    public SimpleContainer(java.util.function.Supplier<? extends org.bukkit.inventory.InventoryHolder> bukkitOwnerCreator, int size) {
+        this(size);
+        this.bukkitOwnerCreator = bukkitOwnerCreator;
+    }
+    // Paper end - Add missing InventoryHolders
+
+    public SimpleContainer(int i, org.bukkit.inventory.InventoryHolder owner) {
+        this.bukkitOwner = owner;
+        // CraftBukkit end
+        this.size = i;
+        this.items = NonNullList.withSize(i, ItemStack.EMPTY);
     }
 
     public SimpleContainer(ItemStack... items) {
@@ -41,87 +123,99 @@
         if (this.listeners != null) {
             this.listeners.remove(listener);
         }
+
     }
 
     @Override
     public ItemStack getItem(int slot) {
-        return slot >= 0 && slot < this.items.size() ? this.items.get(slot) : ItemStack.EMPTY;
+        return slot >= 0 && slot < this.items.size() ? (ItemStack) this.items.get(slot) : ItemStack.EMPTY;
     }
 
     public List<ItemStack> removeAllItems() {
-        List<ItemStack> list = this.items.stream().filter(stack -> !stack.isEmpty()).collect(Collectors.toList());
+        List<ItemStack> list = (List) this.items.stream().filter((itemstack) -> {
+            return !itemstack.isEmpty();
+        }).collect(Collectors.toList());
+
         this.clearContent();
         return list;
     }
 
     @Override
     public ItemStack removeItem(int slot, int amount) {
-        ItemStack itemStack = ContainerHelper.removeItem(this.items, slot, amount);
-        if (!itemStack.isEmpty()) {
+        ItemStack itemstack = ContainerHelper.removeItem(this.items, slot, amount);
+
+        if (!itemstack.isEmpty()) {
             this.setChanged();
         }
 
-        return itemStack;
+        return itemstack;
     }
 
     public ItemStack removeItemType(Item item, int count) {
-        ItemStack itemStack = new ItemStack(item, 0);
+        ItemStack itemstack = new ItemStack(item, 0);
 
-        for (int i = this.size - 1; i >= 0; i--) {
-            ItemStack itemStack2 = this.getItem(i);
-            if (itemStack2.getItem().equals(item)) {
-                int j = count - itemStack.getCount();
-                ItemStack itemStack3 = itemStack2.split(j);
-                itemStack.grow(itemStack3.getCount());
-                if (itemStack.getCount() == count) {
+        for (int j = this.size - 1; j >= 0; --j) {
+            ItemStack itemstack1 = this.getItem(j);
+
+            if (itemstack1.getItem().equals(item)) {
+                int k = count - itemstack.getCount();
+                ItemStack itemstack2 = itemstack1.split(k);
+
+                itemstack.grow(itemstack2.getCount());
+                if (itemstack.getCount() == count) {
                     break;
                 }
             }
         }
 
-        if (!itemStack.isEmpty()) {
+        if (!itemstack.isEmpty()) {
             this.setChanged();
         }
 
-        return itemStack;
+        return itemstack;
     }
 
     public ItemStack addItem(ItemStack stack) {
         if (stack.isEmpty()) {
             return ItemStack.EMPTY;
         } else {
-            ItemStack itemStack = stack.copy();
-            this.moveItemToOccupiedSlotsWithSameType(itemStack);
-            if (itemStack.isEmpty()) {
+            ItemStack itemstack1 = stack.copy();
+
+            this.moveItemToOccupiedSlotsWithSameType(itemstack1);
+            if (itemstack1.isEmpty()) {
                 return ItemStack.EMPTY;
             } else {
-                this.moveItemToEmptySlots(itemStack);
-                return itemStack.isEmpty() ? ItemStack.EMPTY : itemStack;
+                this.moveItemToEmptySlots(itemstack1);
+                return itemstack1.isEmpty() ? ItemStack.EMPTY : itemstack1;
             }
         }
     }
 
     public boolean canAddItem(ItemStack stack) {
-        boolean bl = false;
+        boolean flag = false;
+        Iterator iterator = this.items.iterator();
 
-        for (ItemStack itemStack : this.items) {
-            if (itemStack.isEmpty() || ItemStack.isSameItemSameComponents(itemStack, stack) && itemStack.getCount() < itemStack.getMaxStackSize()) {
-                bl = true;
+        while (iterator.hasNext()) {
+            ItemStack itemstack1 = (ItemStack) iterator.next();
+
+            if (itemstack1.isEmpty() || ItemStack.isSameItemSameComponents(itemstack1, stack) && itemstack1.getCount() < itemstack1.getMaxStackSize()) {
+                flag = true;
                 break;
             }
         }
 
-        return bl;
+        return flag;
     }
 
     @Override
     public ItemStack removeItemNoUpdate(int slot) {
-        ItemStack itemStack = this.items.get(slot);
-        if (itemStack.isEmpty()) {
+        ItemStack itemstack = (ItemStack) this.items.get(slot);
+
+        if (itemstack.isEmpty()) {
             return ItemStack.EMPTY;
         } else {
             this.items.set(slot, ItemStack.EMPTY);
-            return itemStack;
+            return itemstack;
         }
     }
 
@@ -139,22 +233,33 @@
 
     @Override
     public boolean isEmpty() {
-        for (ItemStack itemStack : this.items) {
-            if (!itemStack.isEmpty()) {
-                return false;
+        Iterator iterator = this.items.iterator();
+
+        ItemStack itemstack;
+
+        do {
+            if (!iterator.hasNext()) {
+                return true;
             }
-        }
 
-        return true;
+            itemstack = (ItemStack) iterator.next();
+        } while (itemstack.isEmpty());
+
+        return false;
     }
 
     @Override
     public void setChanged() {
         if (this.listeners != null) {
-            for (ContainerListener containerListener : this.listeners) {
-                containerListener.containerChanged(this);
+            Iterator iterator = this.listeners.iterator();
+
+            while (iterator.hasNext()) {
+                ContainerListener iinventorylistener = (ContainerListener) iterator.next();
+
+                iinventorylistener.containerChanged(this);
             }
         }
+
     }
 
     @Override
@@ -170,67 +275,81 @@
 
     @Override
     public void fillStackedContents(StackedContents finder) {
-        for (ItemStack itemStack : this.items) {
-            finder.accountStack(itemStack);
+        Iterator iterator = this.items.iterator();
+
+        while (iterator.hasNext()) {
+            ItemStack itemstack = (ItemStack) iterator.next();
+
+            finder.accountStack(itemstack);
         }
+
     }
 
-    @Override
     public String toString() {
-        return this.items.stream().filter(stack -> !stack.isEmpty()).collect(Collectors.toList()).toString();
+        return ((List) this.items.stream().filter((itemstack) -> {
+            return !itemstack.isEmpty();
+        }).collect(Collectors.toList())).toString();
     }
 
     private void moveItemToEmptySlots(ItemStack stack) {
-        for (int i = 0; i < this.size; i++) {
-            ItemStack itemStack = this.getItem(i);
-            if (itemStack.isEmpty()) {
+        for (int i = 0; i < this.size; ++i) {
+            ItemStack itemstack1 = this.getItem(i);
+
+            if (itemstack1.isEmpty()) {
                 this.setItem(i, stack.copyAndClear());
                 return;
             }
         }
+
     }
 
     private void moveItemToOccupiedSlotsWithSameType(ItemStack stack) {
-        for (int i = 0; i < this.size; i++) {
-            ItemStack itemStack = this.getItem(i);
-            if (ItemStack.isSameItemSameComponents(itemStack, stack)) {
-                this.moveItemsBetweenStacks(stack, itemStack);
+        for (int i = 0; i < this.size; ++i) {
+            ItemStack itemstack1 = this.getItem(i);
+
+            if (ItemStack.isSameItemSameComponents(itemstack1, stack)) {
+                this.moveItemsBetweenStacks(stack, itemstack1);
                 if (stack.isEmpty()) {
                     return;
                 }
             }
         }
+
     }
 
     private void moveItemsBetweenStacks(ItemStack source, ItemStack target) {
         int i = this.getMaxStackSize(target);
         int j = Math.min(source.getCount(), i - target.getCount());
+
         if (j > 0) {
             target.grow(j);
             source.shrink(j);
             this.setChanged();
         }
+
     }
 
     public void fromTag(ListTag list, HolderLookup.Provider registries) {
         this.clearContent();
 
-        for (int i = 0; i < list.size(); i++) {
+        for (int i = 0; i < list.size(); ++i) {
             ItemStack.parse(registries, list.getCompound(i)).ifPresent(this::addItem);
         }
+
     }
 
     public ListTag createTag(HolderLookup.Provider registries) {
-        ListTag listTag = new ListTag();
+        ListTag nbttaglist = new ListTag();
 
-        for (int i = 0; i < this.getContainerSize(); i++) {
-            ItemStack itemStack = this.getItem(i);
-            if (!itemStack.isEmpty()) {
-                listTag.add(itemStack.save(registries));
+        for (int i = 0; i < this.getContainerSize(); ++i) {
+            ItemStack itemstack = this.getItem(i);
+
+            if (!itemstack.isEmpty()) {
+                nbttaglist.add(itemstack.save(registries));
             }
         }
 
-        return listTag;
+        return nbttaglist;
     }
 
     public NonNullList<ItemStack> getItems() {
