--- a/net/minecraft/world/entity/player/Inventory.java
+++ b/net/minecraft/world/entity/player/Inventory.java
@@ -56,6 +_,80 @@
     public final Player player;
     public final EntityEquipment equipment;
     private int timesChanged;
+    // Paper start - add fields and methods
+    public static final EquipmentSlot[] EQUIPMENT_SLOTS_SORTED_BY_INDEX = EQUIPMENT_SLOT_MAPPING.int2ObjectEntrySet()
+        .stream()
+        .sorted(java.util.Comparator.comparingInt(it.unimi.dsi.fastutil.ints.Int2ObjectMap.Entry::getIntKey))
+        .map(java.util.Map.Entry::getValue).toArray(EquipmentSlot[]::new);
+    public java.util.List<org.bukkit.entity.HumanEntity> transaction = new java.util.ArrayList<>();
+    private int maxStack = MAX_STACK;
+
+    @Override
+    public java.util.List<ItemStack> getContents() {
+        java.util.List<ItemStack> combined = new java.util.ArrayList<>(this.items.size() + EQUIPMENT_SLOT_MAPPING.size());
+        combined.addAll(this.items);
+        for (EquipmentSlot equipmentSlot : EQUIPMENT_SLOTS_SORTED_BY_INDEX) {
+            ItemStack itemStack = this.equipment.get(equipmentSlot);
+            combined.add(itemStack); // Include empty items
+        };
+        return combined;
+    }
+
+    public java.util.List<ItemStack> getArmorContents() {
+        java.util.List<ItemStack> items = new java.util.ArrayList<>(4);
+        for (EquipmentSlot equipmentSlot : EQUIPMENT_SLOTS_SORTED_BY_INDEX) {
+            if (equipmentSlot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR) {
+                items.add(this.equipment.get(equipmentSlot));
+            }
+        }
+        return items;
+    }
+
+    public java.util.List<ItemStack> getExtraContent() {
+        java.util.List<ItemStack> items = new java.util.ArrayList<>();
+        for (EquipmentSlot equipmentSlot : EQUIPMENT_SLOTS_SORTED_BY_INDEX) {
+            if (equipmentSlot.getType() != EquipmentSlot.Type.HUMANOID_ARMOR) { // Non humanoid armor is considered extra
+                items.add(this.equipment.get(equipmentSlot));
+            }
+        }
+        return items;
+    }
+
+    @Override
+    public void onOpen(org.bukkit.craftbukkit.entity.CraftHumanEntity player) {
+        this.transaction.add(player);
+    }
+
+    @Override
+    public void onClose(org.bukkit.craftbukkit.entity.CraftHumanEntity player) {
+        this.transaction.remove(player);
+    }
+
+    @Override
+    public java.util.List<org.bukkit.entity.HumanEntity> getViewers() {
+        return this.transaction;
+    }
+
+    @Override
+    public org.bukkit.inventory.InventoryHolder getOwner() {
+        return this.player.getBukkitEntity();
+    }
+
+    @Override
+    public int getMaxStackSize() {
+        return this.maxStack;
+    }
+
+    @Override
+    public void setMaxStackSize(int size) {
+        this.maxStack = size;
+    }
+
+    @Override
+    public org.bukkit.Location getLocation() {
+        return this.player.getBukkitEntity().getLocation();
+    }
+    // Paper end - add fields and methods
 
     public Inventory(Player player, EntityEquipment equipment) {
         this.player = player;
@@ -92,10 +_,39 @@
 
     private boolean hasRemainingSpaceForItem(ItemStack destination, ItemStack origin) {
         return !destination.isEmpty()
-            && ItemStack.isSameItemSameComponents(destination, origin)
             && destination.isStackable()
-            && destination.getCount() < this.getMaxStackSize(destination);
-    }
+            && destination.getCount() < this.getMaxStackSize(destination)
+            && ItemStack.isSameItemSameComponents(destination, origin); // Paper - check if itemstack is stackable first
+    }
+
+    // CraftBukkit start - Watch method above! :D
+    public int canHold(ItemStack itemStack) {
+        int remains = itemStack.getCount();
+        for (int slot = 0; slot < this.items.size(); ++slot) {
+            ItemStack itemInSlot = this.getItem(slot);
+            if (itemInSlot.isEmpty()) {
+                return itemStack.getCount();
+            }
+
+            if (this.hasRemainingSpaceForItem(itemInSlot, itemStack)) {
+                remains -= (itemInSlot.getMaxStackSize() < this.getMaxStackSize() ? itemInSlot.getMaxStackSize() : this.getMaxStackSize()) - itemInSlot.getCount();
+            }
+            if (remains <= 0) {
+                return itemStack.getCount();
+            }
+        }
+
+        ItemStack itemInOffhand = this.equipment.get(EquipmentSlot.OFFHAND);
+        if (this.hasRemainingSpaceForItem(itemInOffhand, itemStack)) {
+            remains -= (itemInOffhand.getMaxStackSize() < this.getMaxStackSize() ? itemInOffhand.getMaxStackSize() : this.getMaxStackSize()) - itemInOffhand.getCount();
+        }
+        if (remains <= 0) {
+            return itemStack.getCount();
+        }
+
+        return itemStack.getCount() - remains;
+    }
+    // CraftBukkit end
 
     public int getFreeSlot() {
         for (int i = 0; i < this.items.size(); i++) {
@@ -107,8 +_,10 @@
         return -1;
     }
 
-    public void addAndPickItem(ItemStack stack) {
-        this.setSelectedSlot(this.getSuitableHotbarSlot());
+    // Paper start - Add PlayerPickItemEvent
+    public void addAndPickItem(ItemStack stack, final int targetSlot) {
+        this.setSelectedSlot(targetSlot);
+        // Paper end - Add PlayerPickItemEvent
         if (!this.items.get(this.selected).isEmpty()) {
             int freeSlot = this.getFreeSlot();
             if (freeSlot != -1) {
@@ -119,8 +_,10 @@
         this.items.set(this.selected, stack);
     }
 
-    public void pickSlot(int index) {
-        this.setSelectedSlot(this.getSuitableHotbarSlot());
+    // Paper start - Add PlayerPickItemEvent
+    public void pickSlot(int index, final int targetSlot) {
+        this.setSelectedSlot(targetSlot);
+    // Paper end - Add PlayerPickItemEvent
         ItemStack itemStack = this.items.get(this.selected);
         this.items.set(this.selected, this.items.get(index));
         this.items.set(index, itemStack);
