--- a/net/minecraft/world/inventory/InventoryMenu.java
+++ b/net/minecraft/world/inventory/InventoryMenu.java
@@ -2,6 +2,7 @@
 
 import com.mojang.datafixers.util.Pair;
 import java.util.Map;
+import net.minecraft.network.chat.Component;
 import net.minecraft.resources.ResourceLocation;
 import net.minecraft.world.Container;
 import net.minecraft.world.entity.EquipmentSlot;
@@ -12,8 +13,12 @@
 import net.minecraft.world.item.crafting.CraftingInput;
 import net.minecraft.world.item.crafting.CraftingRecipe;
 import net.minecraft.world.item.crafting.RecipeHolder;
+import org.bukkit.craftbukkit.inventory.CraftInventoryCrafting;
+import org.bukkit.craftbukkit.inventory.CraftInventoryView;
+// CraftBukkit end
 
 public class InventoryMenu extends RecipeBookMenu<CraftingInput, CraftingRecipe> {
+
     public static final int CONTAINER_ID = 0;
     public static final int RESULT_SLOT = 0;
     public static final int CRAFT_SLOT_START = 1;
@@ -33,51 +38,59 @@
     public static final ResourceLocation EMPTY_ARMOR_SLOT_LEGGINGS = ResourceLocation.withDefaultNamespace("item/empty_armor_slot_leggings");
     public static final ResourceLocation EMPTY_ARMOR_SLOT_BOOTS = ResourceLocation.withDefaultNamespace("item/empty_armor_slot_boots");
     public static final ResourceLocation EMPTY_ARMOR_SLOT_SHIELD = ResourceLocation.withDefaultNamespace("item/empty_armor_slot_shield");
-    private static final Map<EquipmentSlot, ResourceLocation> TEXTURE_EMPTY_SLOTS = Map.of(
-        EquipmentSlot.FEET,
-        EMPTY_ARMOR_SLOT_BOOTS,
-        EquipmentSlot.LEGS,
-        EMPTY_ARMOR_SLOT_LEGGINGS,
-        EquipmentSlot.CHEST,
-        EMPTY_ARMOR_SLOT_CHESTPLATE,
-        EquipmentSlot.HEAD,
-        EMPTY_ARMOR_SLOT_HELMET
-    );
+    private static final Map<EquipmentSlot, ResourceLocation> TEXTURE_EMPTY_SLOTS = Map.of(EquipmentSlot.FEET, InventoryMenu.EMPTY_ARMOR_SLOT_BOOTS, EquipmentSlot.LEGS, InventoryMenu.EMPTY_ARMOR_SLOT_LEGGINGS, EquipmentSlot.CHEST, InventoryMenu.EMPTY_ARMOR_SLOT_CHESTPLATE, EquipmentSlot.HEAD, InventoryMenu.EMPTY_ARMOR_SLOT_HELMET);
     private static final EquipmentSlot[] SLOT_IDS = new EquipmentSlot[]{EquipmentSlot.HEAD, EquipmentSlot.CHEST, EquipmentSlot.LEGS, EquipmentSlot.FEET};
-    private final CraftingContainer craftSlots = new TransientCraftingContainer(this, 2, 2);
-    private final ResultContainer resultSlots = new ResultContainer();
+    // CraftBukkit start
+    private final TransientCraftingContainer craftSlots;
+    private final ResultContainer resultSlots;
+    // CraftBukkit end
     public final boolean active;
     private final Player owner;
+    // CraftBukkit start
+    private CraftInventoryView bukkitEntity = null;
+    private Inventory player;
+    // CraftBukkit end
 
-    public InventoryMenu(Inventory inventory, boolean onServer, Player owner) {
-        super(null, 0);
+    public InventoryMenu(Inventory inventory, boolean onServer, final Player owner) {
+        super((MenuType) null, 0);
         this.active = onServer;
         this.owner = owner;
+        // CraftBukkit start
+        this.resultSlots = new ResultContainer(); // CraftBukkit - moved to before InventoryCrafting construction
+        this.craftSlots = new TransientCraftingContainer(this, 2, 2, inventory.player); // CraftBukkit - pass player
+        this.craftSlots.resultInventory = this.resultSlots; // CraftBukkit - let InventoryCrafting know about its result slot
+        this.player = inventory; // CraftBukkit - save player
+        this.setTitle(Component.translatable("container.crafting")); // SPIGOT-4722: Allocate title for player inventory
+        // CraftBukkit end
         this.addSlot(new ResultSlot(inventory.player, this.craftSlots, this.resultSlots, 0, 154, 28));
 
-        for (int i = 0; i < 2; i++) {
-            for (int j = 0; j < 2; j++) {
+        int i;
+        int j;
+
+        for (i = 0; i < 2; ++i) {
+            for (j = 0; j < 2; ++j) {
                 this.addSlot(new Slot(this.craftSlots, j + i * 2, 98 + j * 18, 18 + i * 18));
             }
         }
 
-        for (int k = 0; k < 4; k++) {
-            EquipmentSlot equipmentSlot = SLOT_IDS[k];
-            ResourceLocation resourceLocation = TEXTURE_EMPTY_SLOTS.get(equipmentSlot);
-            this.addSlot(new ArmorSlot(inventory, owner, equipmentSlot, 39 - k, 8, 8 + k * 18, resourceLocation));
+        for (i = 0; i < 4; ++i) {
+            EquipmentSlot enumitemslot = InventoryMenu.SLOT_IDS[i];
+            ResourceLocation minecraftkey = (ResourceLocation) InventoryMenu.TEXTURE_EMPTY_SLOTS.get(enumitemslot);
+
+            this.addSlot(new ArmorSlot(inventory, owner, enumitemslot, 39 - i, 8, 8 + i * 18, minecraftkey));
         }
 
-        for (int l = 0; l < 3; l++) {
-            for (int m = 0; m < 9; m++) {
-                this.addSlot(new Slot(inventory, m + (l + 1) * 9, 8 + m * 18, 84 + l * 18));
+        for (i = 0; i < 3; ++i) {
+            for (j = 0; j < 9; ++j) {
+                this.addSlot(new Slot(inventory, j + (i + 1) * 9, 8 + j * 18, 84 + i * 18));
             }
         }
 
-        for (int n = 0; n < 9; n++) {
-            this.addSlot(new Slot(inventory, n, 8 + n * 18, 142));
+        for (i = 0; i < 9; ++i) {
+            this.addSlot(new Slot(inventory, i, 8 + i * 18, 142));
         }
 
-        this.addSlot(new Slot(inventory, 40, 77, 62) {
+        this.addSlot(new Slot(inventory, 40, 77, 62) { // CraftBukkit - decompile error
             @Override
             public void setByPlayer(ItemStack stack, ItemStack previousStack) {
                 owner.onEquipItem(EquipmentSlot.OFFHAND, previousStack, stack);
@@ -108,12 +121,12 @@
 
     @Override
     public boolean recipeMatches(RecipeHolder<CraftingRecipe> recipe) {
-        return recipe.value().matches(this.craftSlots.asCraftInput(), this.owner.level());
+        return ((CraftingRecipe) recipe.value()).matches(this.craftSlots.asCraftInput(), this.owner.level());
     }
 
     @Override
     public void slotsChanged(Container inventory) {
-        CraftingMenu.slotChangedCraftingGrid(this, this.owner.level(), this.owner, this.craftSlots, this.resultSlots, null);
+        CraftingMenu.slotChangedCraftingGrid(this, this.owner.level(), this.owner, this.craftSlots, this.resultSlots, (RecipeHolder) null);
     }
 
     @Override
@@ -132,64 +145,68 @@
 
     @Override
     public ItemStack quickMoveStack(Player player, int slot) {
-        ItemStack itemStack = ItemStack.EMPTY;
-        Slot slot2 = this.slots.get(slot);
-        if (slot2.hasItem()) {
-            ItemStack itemStack2 = slot2.getItem();
-            itemStack = itemStack2.copy();
-            EquipmentSlot equipmentSlot = player.getEquipmentSlotForItem(itemStack);
+        ItemStack itemstack = ItemStack.EMPTY;
+        Slot slot1 = (Slot) this.slots.get(slot);
+
+        if (slot1.hasItem()) {
+            ItemStack itemstack1 = slot1.getItem();
+
+            itemstack = itemstack1.copy();
+            EquipmentSlot enumitemslot = player.getEquipmentSlotForItem(itemstack);
+
             if (slot == 0) {
-                if (!this.moveItemStackTo(itemStack2, 9, 45, true)) {
+                if (!this.moveItemStackTo(itemstack1, 9, 45, true)) {
                     return ItemStack.EMPTY;
                 }
 
-                slot2.onQuickCraft(itemStack2, itemStack);
+                slot1.onQuickCraft(itemstack1, itemstack);
             } else if (slot >= 1 && slot < 5) {
-                if (!this.moveItemStackTo(itemStack2, 9, 45, false)) {
+                if (!this.moveItemStackTo(itemstack1, 9, 45, false)) {
                     return ItemStack.EMPTY;
                 }
             } else if (slot >= 5 && slot < 9) {
-                if (!this.moveItemStackTo(itemStack2, 9, 45, false)) {
+                if (!this.moveItemStackTo(itemstack1, 9, 45, false)) {
                     return ItemStack.EMPTY;
                 }
-            } else if (equipmentSlot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR && !this.slots.get(8 - equipmentSlot.getIndex()).hasItem()) {
-                int i = 8 - equipmentSlot.getIndex();
-                if (!this.moveItemStackTo(itemStack2, i, i + 1, false)) {
+            } else if (enumitemslot.getType() == EquipmentSlot.Type.HUMANOID_ARMOR && !((Slot) this.slots.get(8 - enumitemslot.getIndex())).hasItem()) {
+                int j = 8 - enumitemslot.getIndex();
+
+                if (!this.moveItemStackTo(itemstack1, j, j + 1, false)) {
                     return ItemStack.EMPTY;
                 }
-            } else if (equipmentSlot == EquipmentSlot.OFFHAND && !this.slots.get(45).hasItem()) {
-                if (!this.moveItemStackTo(itemStack2, 45, 46, false)) {
+            } else if (enumitemslot == EquipmentSlot.OFFHAND && !((Slot) this.slots.get(45)).hasItem()) {
+                if (!this.moveItemStackTo(itemstack1, 45, 46, false)) {
                     return ItemStack.EMPTY;
                 }
             } else if (slot >= 9 && slot < 36) {
-                if (!this.moveItemStackTo(itemStack2, 36, 45, false)) {
+                if (!this.moveItemStackTo(itemstack1, 36, 45, false)) {
                     return ItemStack.EMPTY;
                 }
             } else if (slot >= 36 && slot < 45) {
-                if (!this.moveItemStackTo(itemStack2, 9, 36, false)) {
+                if (!this.moveItemStackTo(itemstack1, 9, 36, false)) {
                     return ItemStack.EMPTY;
                 }
-            } else if (!this.moveItemStackTo(itemStack2, 9, 45, false)) {
+            } else if (!this.moveItemStackTo(itemstack1, 9, 45, false)) {
                 return ItemStack.EMPTY;
             }
 
-            if (itemStack2.isEmpty()) {
-                slot2.setByPlayer(ItemStack.EMPTY, itemStack);
+            if (itemstack1.isEmpty()) {
+                slot1.setByPlayer(ItemStack.EMPTY, itemstack);
             } else {
-                slot2.setChanged();
+                slot1.setChanged();
             }
 
-            if (itemStack2.getCount() == itemStack.getCount()) {
+            if (itemstack1.getCount() == itemstack.getCount()) {
                 return ItemStack.EMPTY;
             }
 
-            slot2.onTake(player, itemStack2);
+            slot1.onTake(player, itemstack1);
             if (slot == 0) {
-                player.drop(itemStack2, false);
+                player.drop(itemstack1, false);
             }
         }
 
-        return itemStack;
+        return itemstack;
     }
 
     @Override
@@ -230,4 +247,17 @@
     public boolean shouldMoveToInventory(int index) {
         return index != this.getResultSlotIndex();
     }
+
+    // CraftBukkit start
+    @Override
+    public CraftInventoryView getBukkitView() {
+        if (this.bukkitEntity != null) {
+            return this.bukkitEntity;
+        }
+
+        CraftInventoryCrafting inventory = new CraftInventoryCrafting(this.craftSlots, this.resultSlots);
+        this.bukkitEntity = new CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this);
+        return this.bukkitEntity;
+    }
+    // CraftBukkit end
 }
