From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jake Potrebic <jake.m.potrebic@gmail.com>
Date: Mon, 24 Jan 2022 00:09:02 -0800
Subject: [PATCH] Add missing InventoryHolders to inventories


diff --git a/src/main/java/net/minecraft/world/Container.java b/src/main/java/net/minecraft/world/Container.java
index db41ffbd24adccd78edf3368ba1f7a3ab9f6072c..5db5ba026462ca642dcee718af732f80fadabef5 100644
--- a/src/main/java/net/minecraft/world/Container.java
+++ b/src/main/java/net/minecraft/world/Container.java
@@ -103,7 +103,7 @@ public interface Container extends Clearable {
 
     java.util.List<org.bukkit.entity.HumanEntity> getViewers();
 
-    org.bukkit.inventory.InventoryHolder getOwner();
+    org.bukkit.inventory.@org.jetbrains.annotations.Nullable InventoryHolder getOwner(); // Paper - annotation
 
     void setMaxStackSize(int size);
 
diff --git a/src/main/java/net/minecraft/world/SimpleContainer.java b/src/main/java/net/minecraft/world/SimpleContainer.java
index b0963c534afe5be164701cb283f1849e32ae5a86..7ed52b887c4d766c23220a8809914d5d80f12ea4 100644
--- a/src/main/java/net/minecraft/world/SimpleContainer.java
+++ b/src/main/java/net/minecraft/world/SimpleContainer.java
@@ -30,7 +30,7 @@ public class SimpleContainer implements Container, StackedContentsCompatible {
     // CraftBukkit start - add fields and methods
     public List<HumanEntity> transaction = new java.util.ArrayList<HumanEntity>();
     private int maxStack = MAX_STACK;
-    protected org.bukkit.inventory.InventoryHolder bukkitOwner;
+    protected @Nullable org.bukkit.inventory.InventoryHolder bukkitOwner; // Paper - annotation
 
     public List<ItemStack> getContents() {
         return this.items;
@@ -58,6 +58,11 @@ public class SimpleContainer implements Container, StackedContentsCompatible {
     }
 
     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;
     }
 
@@ -86,6 +91,13 @@ public class SimpleContainer implements Container, StackedContentsCompatible {
     public SimpleContainer(int size) {
         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;
diff --git a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
index 22dc1569aabe69f139d9682ceb81311993706cb8..85caec29a705f216eff8a5ae11f250697891a05c 100644
--- a/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/AbstractContainerMenu.java
@@ -1054,4 +1054,15 @@ public abstract class AbstractContainerMenu {
         this.stateId = this.stateId + 1 & 32767;
         return this.stateId;
     }
+
+    // Paper start - Add missing InventoryHolders
+    // The reason this is a supplier, is that the createHolder method uses the bukkit InventoryView#getTopInventory to get the inventory in question
+    // and that can't be obtained safely until the AbstractContainerMenu has been fully constructed. Using a supplier lazily
+    // initializes the InventoryHolder safely.
+    protected final Supplier<org.bukkit.inventory.BlockInventoryHolder> createBlockHolder(final ContainerLevelAccess context) {
+        //noinspection ConstantValue
+        Preconditions.checkArgument(context != null, "context was null");
+        return () -> context.createBlockHolder(this);
+    }
+    // Paper end - Add missing InventoryHolders
 }
diff --git a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java
index c0dfa04511110be366ee5b0bd75efc51afcce2e4..e0ee1c10960d24d2369d16f22431a8e02a5570aa 100644
--- a/src/main/java/net/minecraft/world/inventory/BeaconMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/BeaconMenu.java
@@ -42,7 +42,7 @@ public class BeaconMenu extends AbstractContainerMenu {
     public BeaconMenu(int syncId, Container inventory, ContainerData propertyDelegate, ContainerLevelAccess context) {
         super(MenuType.BEACON, syncId);
         this.player = (Inventory) inventory; // CraftBukkit - TODO: check this
-        this.beacon = new SimpleContainer(1) { // CraftBukkit - decompile error
+        this.beacon = new SimpleContainer(this.createBlockHolder(context), 1) { // CraftBukkit - decompile error // Paper - Add missing InventoryHolders
             @Override
             public boolean canPlaceItem(int slot, ItemStack stack) {
                 return stack.is(ItemTags.BEACON_PAYMENT_ITEMS);
diff --git a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
index 8b72d1fd551dcb113f4137aee441a9531c00288a..b3a16b024e46ee8203b225ee429a5c973eab12c6 100644
--- a/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/CartographyTableMenu.java
@@ -54,7 +54,7 @@ public class CartographyTableMenu extends AbstractContainerMenu {
 
     public CartographyTableMenu(int syncId, Inventory inventory, final ContainerLevelAccess context) {
         super(MenuType.CARTOGRAPHY_TABLE, syncId);
-        this.container = new SimpleContainer(2) {
+        this.container = new SimpleContainer(this.createBlockHolder(context), 2) { // Paper - Add missing InventoryHolders
             @Override
             public void setChanged() {
                 CartographyTableMenu.this.slotsChanged(this);
@@ -68,7 +68,7 @@ public class CartographyTableMenu extends AbstractContainerMenu {
             }
             // CraftBukkit end
         };
-        this.resultContainer = new ResultContainer() {
+        this.resultContainer = new ResultContainer(this.createBlockHolder(context)) { // Paper - Add missing InventoryHolders
             @Override
             public void setChanged() {
                 CartographyTableMenu.this.slotsChanged(this);
diff --git a/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java b/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java
index 85e336637db8643fc5aca1dba724c9b341cbf46f..12b466ccb7c36021cf807c4f3fd2bcb037943abc 100644
--- a/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java
+++ b/src/main/java/net/minecraft/world/inventory/ContainerLevelAccess.java
@@ -21,6 +21,18 @@ public interface ContainerLevelAccess {
         return new org.bukkit.Location(this.getWorld().getWorld(), this.getPosition().getX(), this.getPosition().getY(), this.getPosition().getZ());
     }
     // CraftBukkit end
+    // Paper start - Add missing InventoryHolders
+    default boolean isBlock() {
+        return false;
+    }
+
+    default org.bukkit.inventory.@org.jetbrains.annotations.Nullable BlockInventoryHolder createBlockHolder(AbstractContainerMenu menu) {
+        if (!this.isBlock()) {
+            return null;
+        }
+        return new org.bukkit.craftbukkit.inventory.CraftBlockInventoryHolder(this, menu.getBukkitView().getTopInventory());
+    }
+    // Paper end - Add missing InventoryHolders
 
     ContainerLevelAccess NULL = new ContainerLevelAccess() {
         @Override
@@ -48,6 +60,12 @@ public interface ContainerLevelAccess {
                 return pos;
             }
             // CraftBukkit end
+            // Paper start - Add missing InventoryHolders
+            @Override
+            public boolean isBlock() {
+                return true;
+            }
+            // Paper end - Add missing InventoryHolders
 
             @Override
             public <T> Optional<T> evaluate(BiFunction<Level, BlockPos, T> getter) {
diff --git a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java
index 2642d8ddc79ad97675f958c89ef03da39903f359..36496144dd6fa87163b692034570eba70c83678c 100644
--- a/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/EnchantmentMenu.java
@@ -63,7 +63,7 @@ public class EnchantmentMenu extends AbstractContainerMenu {
 
     public EnchantmentMenu(int syncId, Inventory playerInventory, ContainerLevelAccess context) {
         super(MenuType.ENCHANTMENT, syncId);
-        this.enchantSlots = new SimpleContainer(2) {
+        this.enchantSlots = new SimpleContainer(this.createBlockHolder(context), 2) { // Paper - Add missing InventoryHolders
             @Override
             public void setChanged() {
                 super.setChanged();
diff --git a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
index 8e58dbb4b110338dfe8add26697d0b1c9ec5fa9c..3b303d41b9facfb2892ff8402ee0de4608db7318 100644
--- a/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/GrindstoneMenu.java
@@ -60,8 +60,8 @@ public class GrindstoneMenu extends AbstractContainerMenu {
 
     public GrindstoneMenu(int syncId, Inventory playerInventory, final ContainerLevelAccess context) {
         super(MenuType.GRINDSTONE, syncId);
-        this.resultSlots = new ResultContainer();
-        this.repairSlots = new SimpleContainer(2) {
+        this.resultSlots = new ResultContainer(this.createBlockHolder(context)); // Paper - Add missing InventoryHolders
+        this.repairSlots = new SimpleContainer(this.createBlockHolder(context), 2) { // Paper - Add missing InventoryHolders
             @Override
             public void setChanged() {
                 super.setChanged();
diff --git a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
index 4734dd90f2a66e1ac7a64b35ecd62a630108cf07..a5d53a656513ae81cc3f9fc506caf6adaba62a8e 100644
--- a/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/ItemCombinerMenu.java
@@ -17,12 +17,7 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu {
     protected final ContainerLevelAccess access;
     protected final Player player;
     protected final Container inputSlots;
-    protected final ResultContainer resultSlots = new ResultContainer() {
-        @Override
-        public void setChanged() {
-            ItemCombinerMenu.this.slotsChanged(this);
-        }
-    };
+    protected final ResultContainer resultSlots; // Paper - Add missing InventoryHolders; delay field init
     private final int resultSlotIndex;
 
     protected boolean mayPickup(Player player, boolean present) {
@@ -36,6 +31,14 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu {
     public ItemCombinerMenu(@Nullable MenuType<?> type, int syncId, Inventory playerInventory, ContainerLevelAccess context, ItemCombinerMenuSlotDefinition forgingSlotsManager) {
         super(type, syncId);
         this.access = context;
+        // Paper start - Add missing InventoryHolders; delay field init
+        this.resultSlots = new ResultContainer(this.createBlockHolder(this.access)) {
+            @Override
+            public void setChanged() {
+                ItemCombinerMenu.this.slotsChanged(this);
+            }
+        };
+        // Paper end - Add missing InventoryHolders; delay field init
         this.player = playerInventory.player;
         this.inputSlots = this.createContainer(forgingSlotsManager.getNumOfInputSlots());
         this.resultSlotIndex = forgingSlotsManager.getResultSlotIndex();
@@ -82,7 +85,7 @@ public abstract class ItemCombinerMenu extends AbstractContainerMenu {
     public abstract void createResult();
 
     private SimpleContainer createContainer(int size) {
-        return new SimpleContainer(size) {
+        return new SimpleContainer(this.createBlockHolder(this.access), size) {
             @Override
             public void setChanged() {
                 super.setChanged();
diff --git a/src/main/java/net/minecraft/world/inventory/LoomMenu.java b/src/main/java/net/minecraft/world/inventory/LoomMenu.java
index 1b7cf165ab0818792870f43719a6324b282bb57a..98519dd3bccca516acdedc69a59189b1106fb75b 100644
--- a/src/main/java/net/minecraft/world/inventory/LoomMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/LoomMenu.java
@@ -73,7 +73,7 @@ public class LoomMenu extends AbstractContainerMenu {
         this.selectablePatterns = List.of();
         this.slotUpdateListener = () -> {
         };
-        this.inputContainer = new SimpleContainer(3) {
+        this.inputContainer = new SimpleContainer(this.createBlockHolder(context), 3) { // Paper - Add missing InventoryHolders
             @Override
             public void setChanged() {
                 super.setChanged();
@@ -88,7 +88,7 @@ public class LoomMenu extends AbstractContainerMenu {
             }
             // CraftBukkit end
         };
-        this.outputContainer = new SimpleContainer(1) {
+        this.outputContainer = new SimpleContainer(this.createBlockHolder(context), 1) { // Paper - Add missing InventoryHolders
             @Override
             public void setChanged() {
                 super.setChanged();
diff --git a/src/main/java/net/minecraft/world/inventory/ResultContainer.java b/src/main/java/net/minecraft/world/inventory/ResultContainer.java
index d4592218d761eb38402e3d95c642e80a708cb333..4c4266a85c38e41e6c7e6144a68624f4daa50c54 100644
--- a/src/main/java/net/minecraft/world/inventory/ResultContainer.java
+++ b/src/main/java/net/minecraft/world/inventory/ResultContainer.java
@@ -29,7 +29,12 @@ public class ResultContainer implements Container, RecipeCraftingHolder {
     }
 
     public org.bukkit.inventory.InventoryHolder getOwner() {
-        return null; // Result slots don't get an owner
+        // Paper start - Add missing InventoryHolders
+        if (this.holder == null && this.holderCreator != null) {
+            this.holder = this.holderCreator.get();
+        }
+        return this.holder; // Result slots don't get an owner
+        // Paper end - Add missing InventoryHolders
     }
 
     // Don't need a transaction; the InventoryCrafting keeps track of it for us
@@ -53,6 +58,14 @@ public class ResultContainer implements Container, RecipeCraftingHolder {
         return null;
     }
     // CraftBukkit end
+    // Paper start - Add missing InventoryHolders
+    private @Nullable java.util.function.Supplier<? extends org.bukkit.inventory.InventoryHolder> holderCreator;
+    private @Nullable org.bukkit.inventory.InventoryHolder holder;
+    public ResultContainer(java.util.function.Supplier<? extends org.bukkit.inventory.InventoryHolder> holderCreator) {
+        this();
+        this.holderCreator = holderCreator;
+    }
+    // Paper end - Add missing InventoryHolders
 
     public ResultContainer() {
         this.itemStacks = NonNullList.withSize(1, ItemStack.EMPTY);
diff --git a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
index a93870952e2ef674028b8a20aa52a685c743e7ea..ca65965757e6f12abc972250a04817c7547bb0bd 100644
--- a/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
+++ b/src/main/java/net/minecraft/world/inventory/StonecutterMenu.java
@@ -69,7 +69,7 @@ public class StonecutterMenu extends AbstractContainerMenu {
         this.input = ItemStack.EMPTY;
         this.slotUpdateListener = () -> {
         };
-        this.container = new SimpleContainer(1) {
+        this.container = new SimpleContainer(this.createBlockHolder(context), 1) { // Paper - Add missing InventoryHolders
             @Override
             public void setChanged() {
                 super.setChanged();
@@ -84,7 +84,7 @@ public class StonecutterMenu extends AbstractContainerMenu {
             }
             // CraftBukkit end
         };
-        this.resultContainer = new ResultContainer();
+        this.resultContainer = new ResultContainer(this.createBlockHolder(context)); // Paper - Add missing InventoryHolders
         this.access = context;
         this.level = playerInventory.player.level();
         this.inputSlot = this.addSlot(new Slot(this.container, 0, 20, 33));
diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlockInventoryHolder.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlockInventoryHolder.java
index 7ae484b0fa5bf5494c6ead15f7f1c0fa840ae270..7129eb5f5cea39992b4c690cb421004004a952ea 100644
--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlockInventoryHolder.java
+++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftBlockInventoryHolder.java
@@ -17,6 +17,13 @@ public class CraftBlockInventoryHolder implements BlockInventoryHolder {
         this.block = CraftBlock.at(world, pos);
         this.inventory = new CraftInventory(inv);
     }
+    // Paper start - Add missing InventoryHolders
+    public CraftBlockInventoryHolder(net.minecraft.world.inventory.ContainerLevelAccess levelAccess, Inventory inventory) {
+        com.google.common.base.Preconditions.checkArgument(levelAccess.isBlock());
+        this.block = CraftBlock.at(levelAccess.getWorld(), levelAccess.getPosition());
+        this.inventory = inventory;
+    }
+    // Paper end - Add missing InventoryHolders
 
     @Override
     public Block getBlock() {