From 501834e57a7a343003c6f81757ec616be95a55dd Mon Sep 17 00:00:00 2001 From: Jake Potrebic Date: Tue, 22 Feb 2022 15:00:45 -0800 Subject: [PATCH] Fix custom inventory holders (#6199) --- build-data/paper.at | 4 + patches/server/0012-Adventure.patch | 13 +- ...store-custom-InventoryHolder-support.patch | 365 ++++++++++++++++-- ...Holder-method-without-block-snapshot.patch | 4 +- 4 files changed, 344 insertions(+), 42 deletions(-) diff --git a/build-data/paper.at b/build-data/paper.at index 6f731e0677..2e798b98b6 100644 --- a/build-data/paper.at +++ b/build-data/paper.at @@ -311,3 +311,7 @@ public-f net.minecraft.world.level.chunk.ChunkGenerator strongholdSeed # More Sculk Sensor API public-f net.minecraft.world.level.gameevent.vibrations.VibrationListener listenerRange + +# Fix custom inventory holders +public-f net.minecraft.world.inventory.AbstractContainerMenu dataSlots +public-f net.minecraft.world.inventory.AbstractContainerMenu remoteDataSlots diff --git a/patches/server/0012-Adventure.patch b/patches/server/0012-Adventure.patch index 4de5d795e0..2549aab060 100644 --- a/patches/server/0012-Adventure.patch +++ b/patches/server/0012-Adventure.patch @@ -3269,20 +3269,15 @@ index ed4415f6dd588c08c922efd5beebb3b124beb9d6..78a7ac47f20e84ccd67ff44d0bc7a2f2 return new CraftInventoryCustom(owner, size, title); } diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftInventoryCreator.java b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftInventoryCreator.java -index 4e705b7367b78c2da98d0b174807ecbce75f3a59..0899afd175f969da0df9371d96d3b5e1de4c8533 100644 +index 4e705b7367b78c2da98d0b174807ecbce75f3a59..4972ce5d876d74e04a4fbfeb860f1d44e25b3470 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftInventoryCreator.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftInventoryCreator.java -@@ -43,6 +43,17 @@ public final class CraftInventoryCreator { +@@ -43,6 +43,12 @@ public final class CraftInventoryCreator { return this.converterMap.get(type).createInventory(holder, type); } + // Paper start + public Inventory createInventory(InventoryHolder holder, InventoryType type, net.kyori.adventure.text.Component title) { -+ // Paper start -+ if (holder != null) { -+ return DEFAULT_CONVERTER.createInventory(holder, type, title); -+ } -+ //noinspection ConstantConditions // Paper end + return converterMap.get(type).createInventory(holder, type, title); + } + // Paper end @@ -3290,7 +3285,7 @@ index 4e705b7367b78c2da98d0b174807ecbce75f3a59..0899afd175f969da0df9371d96d3b5e1 public Inventory createInventory(InventoryHolder holder, InventoryType type, String title) { return this.converterMap.get(type).createInventory(holder, type, title); } -@@ -51,6 +62,12 @@ public final class CraftInventoryCreator { +@@ -51,6 +57,12 @@ public final class CraftInventoryCreator { return this.DEFAULT_CONVERTER.createInventory(holder, size); } @@ -3303,7 +3298,7 @@ index 4e705b7367b78c2da98d0b174807ecbce75f3a59..0899afd175f969da0df9371d96d3b5e1 public Inventory createInventory(InventoryHolder holder, int size, String title) { return this.DEFAULT_CONVERTER.createInventory(holder, size, title); } -@@ -59,6 +76,10 @@ public final class CraftInventoryCreator { +@@ -59,6 +71,10 @@ public final class CraftInventoryCreator { Inventory createInventory(InventoryHolder holder, InventoryType type); diff --git a/patches/server/0286-Restore-custom-InventoryHolder-support.patch b/patches/server/0286-Restore-custom-InventoryHolder-support.patch index 3a5cb7251b..62f1b3a9b0 100644 --- a/patches/server/0286-Restore-custom-InventoryHolder-support.patch +++ b/patches/server/0286-Restore-custom-InventoryHolder-support.patch @@ -1,46 +1,349 @@ From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 -From: Shane Freeder +From: Jake Potrebic Date: Mon, 5 Nov 2018 04:23:51 +0000 Subject: [PATCH] Restore custom InventoryHolder support +Co-authored-by: Shane Freeder + Upstream removed the ability to consistently use a custom InventoryHolder, However, the implementation does not use an InventoryHolder in any form outside of custom inventories. -We can take that knowledge and apply some expected behavior, if we're given -an inventory holder, we should use it and return a custom inventory with the -holder, otherwise, create an inventory backed by the intended inventory, as -per upstream behavior. - -This provides a "best of both worlds" scenario: plugins with InventoryHolder's -will always work as intended in the past, those without will create implementation -based inventories. - -diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftInventoryCreator.java b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftInventoryCreator.java -index 0899afd175f969da0df9371d96d3b5e1de4c8533..fc307213a4bc9675c6011a81e4e06cd23a22926d 100644 ---- a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftInventoryCreator.java -+++ b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftInventoryCreator.java -@@ -40,6 +40,11 @@ public final class CraftInventoryCreator { - } - - public Inventory createInventory(InventoryHolder holder, InventoryType type) { -+ // Paper start -+ if (holder != null) { -+ return this.DEFAULT_CONVERTER.createInventory(holder, type); +diff --git a/src/main/java/io/papermc/paper/inventory/PaperInventoryCustomHolderContainer.java b/src/main/java/io/papermc/paper/inventory/PaperInventoryCustomHolderContainer.java +new file mode 100644 +index 0000000000000000000000000000000000000000..8e02633b2f8676095ca5c5326c88499a8f36c842 +--- /dev/null ++++ b/src/main/java/io/papermc/paper/inventory/PaperInventoryCustomHolderContainer.java +@@ -0,0 +1,140 @@ ++package io.papermc.paper.inventory; ++ ++import io.papermc.paper.adventure.PaperAdventure; ++import net.kyori.adventure.text.Component; ++import net.minecraft.world.Container; ++import net.minecraft.world.entity.player.Player; ++import net.minecraft.world.item.ItemStack; ++import net.minecraft.world.level.block.entity.BaseContainerBlockEntity; ++import org.bukkit.Location; ++import org.bukkit.craftbukkit.entity.CraftHumanEntity; ++import org.bukkit.entity.HumanEntity; ++import org.bukkit.event.inventory.InventoryType; ++import org.bukkit.inventory.InventoryHolder; ++import org.checkerframework.checker.nullness.qual.NonNull; ++import org.checkerframework.checker.nullness.qual.Nullable; ++import org.checkerframework.framework.qual.DefaultQualifier; ++ ++import java.util.List; ++ ++@DefaultQualifier(NonNull.class) ++public final class PaperInventoryCustomHolderContainer implements Container { ++ ++ private final InventoryHolder owner; ++ private final Container delegate; ++ private final InventoryType type; ++ private final String title; ++ private final Component adventure$title; ++ ++ public PaperInventoryCustomHolderContainer(InventoryHolder owner, Container delegate, InventoryType type) { ++ this.owner = owner; ++ this.delegate = delegate; ++ this.type = type; ++ @Nullable Component adventure$title = null; ++ if (delegate instanceof BaseContainerBlockEntity blockEntity) { ++ adventure$title = blockEntity.getCustomName() != null ? PaperAdventure.asAdventure(blockEntity.getCustomName()) : null; + } -+ //noinspection ConstantConditions // Paper end - return this.converterMap.get(type).createInventory(holder, type); ++ if (adventure$title == null) { ++ adventure$title = type.defaultTitle(); ++ } ++ this.adventure$title = adventure$title; ++ this.title = PaperAdventure.LEGACY_SECTION_UXRC.serialize(this.adventure$title); ++ } ++ ++ public Component title() { ++ return this.adventure$title; ++ } ++ ++ public String getTitle() { ++ return this.title; ++ } ++ ++ public InventoryType getType() { ++ return this.type; ++ } ++ ++ @Override ++ public int getContainerSize() { ++ return this.delegate.getContainerSize(); ++ } ++ ++ @Override ++ public boolean isEmpty() { ++ return this.delegate.isEmpty(); ++ } ++ ++ @Override ++ public ItemStack getItem(int slot) { ++ return this.delegate.getItem(slot); ++ } ++ ++ @Override ++ public ItemStack removeItem(int slot, int amount) { ++ return this.delegate.removeItem(slot, amount); ++ } ++ ++ @Override ++ public ItemStack removeItemNoUpdate(int slot) { ++ return this.delegate.removeItemNoUpdate(slot); ++ } ++ ++ @Override ++ public void setItem(int slot, ItemStack stack) { ++ this.delegate.setItem(slot, stack); ++ } ++ ++ @Override ++ public int getMaxStackSize() { ++ return this.delegate.getMaxStackSize(); ++ } ++ ++ @Override ++ public void setChanged() { ++ this.delegate.setChanged(); ++ } ++ ++ @Override ++ public boolean stillValid(Player player) { ++ return this.delegate.stillValid(player); ++ } ++ ++ @Override ++ public List getContents() { ++ return this.delegate.getContents(); ++ } ++ ++ @Override ++ public void onOpen(CraftHumanEntity who) { ++ this.delegate.onOpen(who); ++ } ++ ++ @Override ++ public void onClose(CraftHumanEntity who) { ++ this.delegate.onClose(who); ++ } ++ ++ @Override ++ public List getViewers() { ++ return this.delegate.getViewers(); ++ } ++ ++ @Override ++ public InventoryHolder getOwner() { ++ return this.owner; ++ } ++ ++ @Override ++ public void setMaxStackSize(int size) { ++ this.delegate.setMaxStackSize(size); ++ } ++ ++ @Override ++ public Location getLocation() { ++ return this.delegate.getLocation(); ++ } ++ ++ @Override ++ public void clearContent() { ++ this.delegate.clearContent(); ++ } ++} +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java +index 60fa587ce17e138d2baf8959c26e25ed1db17a4a..c50813f3a3ef78ce053249ca0c93360c0bc22e8d 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftContainer.java +@@ -72,13 +72,13 @@ public class CraftContainer extends AbstractContainerMenu { + // Paper start + @Override + public net.kyori.adventure.text.Component title() { +- return inventory instanceof CraftInventoryCustom ? ((CraftInventoryCustom.MinecraftInventory) ((CraftInventory) inventory).getInventory()).title() : net.kyori.adventure.text.Component.text(inventory.getType().getDefaultTitle()); ++ return inventory instanceof CraftInventoryCustom custom ? custom.title() : inventory.getType().defaultTitle(); // Paper + } + // Paper end + + @Override + public String getTitle() { +- return inventory instanceof CraftInventoryCustom ? ((CraftInventoryCustom.MinecraftInventory) ((CraftInventory) inventory).getInventory()).getTitle() : inventory.getType().getDefaultTitle(); ++ return inventory instanceof CraftInventoryCustom custom ? custom.getTitle() : inventory.getType().getDefaultTitle(); // Paper + } + }, player, id); + } +@@ -230,6 +230,10 @@ public class CraftContainer extends AbstractContainerMenu { + this.lastSlots = delegate.lastSlots; + this.slots = delegate.slots; + this.remoteSlots = delegate.remoteSlots; ++ // Paper start - copy data slots for InventoryView#set/getProperty ++ this.dataSlots = delegate.dataSlots; ++ this.remoteDataSlots = delegate.remoteDataSlots; ++ // Paper end + } + + // SPIGOT-4598 - we should still delegate the shift click handler +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +index 6ca8e76d1569f3f631275fea187e7110f09fc69e..3796f8b122ad981b6faacd2afcaf3696314aad6b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +@@ -490,6 +490,10 @@ public class CraftInventory implements Inventory { + return InventoryType.BREWING; + } else if (this.inventory instanceof CraftInventoryCustom.MinecraftInventory) { + return ((CraftInventoryCustom.MinecraftInventory) this.inventory).getType(); ++ // Paper start ++ } else if (this.inventory instanceof io.papermc.paper.inventory.PaperInventoryCustomHolderContainer holderContainer) { ++ return holderContainer.getType(); ++ // Paper end + } else if (this.inventory instanceof PlayerEnderChestContainer) { + return InventoryType.ENDER_CHEST; + } else if (this.inventory instanceof MerchantContainer) { +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java +index 08fc05836b26f5f93ae74324705d5f593b57315a..fdde2b3f2320393ab4acf450d08ab6744c5408ea 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventoryCustom.java +@@ -15,6 +15,11 @@ import org.bukkit.event.inventory.InventoryType; + import org.bukkit.inventory.InventoryHolder; + + public class CraftInventoryCustom extends CraftInventory { ++ // Paper start ++ public CraftInventoryCustom(InventoryHolder owner, InventoryType type, Container delegate) { ++ super(new io.papermc.paper.inventory.PaperInventoryCustomHolderContainer(owner, delegate, type)); ++ } ++ // Paper end + public CraftInventoryCustom(InventoryHolder owner, InventoryType type) { + super(new MinecraftInventory(owner, type)); + } +@@ -42,6 +47,27 @@ public class CraftInventoryCustom extends CraftInventory { + public CraftInventoryCustom(InventoryHolder owner, int size, String title) { + super(new MinecraftInventory(owner, size, title)); + } ++ // Paper start ++ public String getTitle() { ++ if (this.inventory instanceof MinecraftInventory minecraftInventory) { ++ return minecraftInventory.getTitle(); ++ } else if (this.inventory instanceof io.papermc.paper.inventory.PaperInventoryCustomHolderContainer customHolderContainer) { ++ return customHolderContainer.getTitle(); ++ } else { ++ throw new UnsupportedOperationException(this.inventory.getClass() + " isn't a recognized Container type here"); ++ } ++ } ++ ++ public net.kyori.adventure.text.Component title() { ++ if (this.inventory instanceof MinecraftInventory minecraftInventory) { ++ return minecraftInventory.title(); ++ } else if (this.inventory instanceof io.papermc.paper.inventory.PaperInventoryCustomHolderContainer customHolderContainer) { ++ return customHolderContainer.title(); ++ } else { ++ throw new UnsupportedOperationException(this.inventory.getClass() + " isn't a recognized Container type here"); ++ } ++ } ++ // Paper end + + static class MinecraftInventory implements Container { + private final NonNullList items; +diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java +index 7a7f3f53aef601f124d474d9890e23d87dd96900..54e61b9b058bee2167461aaaf828ed7a00949c29 100644 +--- a/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java ++++ b/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftTileInventoryConverter.java +@@ -28,7 +28,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat + + @Override + public Inventory createInventory(InventoryHolder holder, InventoryType type) { +- return this.getInventory(this.getTileEntity()); ++ return this.getInventory(holder, type, this.getTileEntity()); // Paper } -@@ -55,6 +60,11 @@ public final class CraftInventoryCreator { + // Paper start +@@ -39,7 +39,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat + ((RandomizableContainerBlockEntity) te).setCustomName(io.papermc.paper.adventure.PaperAdventure.asVanilla(title)); + } + +- return getInventory(te); ++ return this.getInventory(owner, type, te); // Paper + } // Paper end - public Inventory createInventory(InventoryHolder holder, InventoryType type, String title) { -+ // Paper start -+ if (holder != null) { -+ return DEFAULT_CONVERTER.createInventory(holder, type, title); -+ } -+ //noinspection ConstantConditions // Paper end - return this.converterMap.get(type).createInventory(holder, type, title); +@@ -50,10 +50,18 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat + ((RandomizableContainerBlockEntity) te).setCustomName(CraftChatMessage.fromStringOrNull(title)); + } + +- return this.getInventory(te); ++ return this.getInventory(holder, type, te); // Paper } ++ @Deprecated // Paper - use getInventory with owner and type + public Inventory getInventory(Container tileEntity) { ++ // Paper start ++ return this.getInventory(null, null, tileEntity); ++ } ++ ++ public Inventory getInventory(InventoryHolder owner, InventoryType type, Container tileEntity) { // Paper ++ if (owner != null) return new org.bukkit.craftbukkit.inventory.CraftInventoryCustom(owner, type, tileEntity); // Paper ++ // Paper end + return new CraftInventory(tileEntity); + } + +@@ -70,7 +78,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat + public Inventory createInventory(InventoryHolder owner, InventoryType type, net.kyori.adventure.text.Component title) { + Container tileEntity = getTileEntity(); + ((AbstractFurnaceBlockEntity) tileEntity).setCustomName(io.papermc.paper.adventure.PaperAdventure.asVanilla(title)); +- return getInventory(tileEntity); ++ return this.getInventory(owner, type, tileEntity); // Paper + } + // Paper end + +@@ -78,11 +86,19 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat + public Inventory createInventory(InventoryHolder owner, InventoryType type, String title) { + Container tileEntity = this.getTileEntity(); + ((AbstractFurnaceBlockEntity) tileEntity).setCustomName(CraftChatMessage.fromStringOrNull(title)); +- return this.getInventory(tileEntity); ++ return this.getInventory(owner, type, tileEntity); // Paper + } + + @Override + public Inventory getInventory(Container tileEntity) { ++ // Paper start ++ return getInventory(null, null, tileEntity); ++ } ++ ++ @Override ++ public Inventory getInventory(InventoryHolder owner, InventoryType type, net.minecraft.world.Container tileEntity) { // Paper ++ if (owner != null) return new org.bukkit.craftbukkit.inventory.CraftInventoryCustom(owner, type, tileEntity); // Paper ++ // Paper end + return new CraftInventoryFurnace((AbstractFurnaceBlockEntity) tileEntity); + } + } +@@ -102,7 +118,7 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat + if (tileEntity instanceof BrewingStandBlockEntity) { + ((BrewingStandBlockEntity) tileEntity).setCustomName(io.papermc.paper.adventure.PaperAdventure.asVanilla(title)); + } +- return getInventory(tileEntity); ++ return this.getInventory(owner, type, tileEntity); // Paper + } + // Paper end + +@@ -113,11 +129,19 @@ public abstract class CraftTileInventoryConverter implements CraftInventoryCreat + if (tileEntity instanceof BrewingStandBlockEntity) { + ((BrewingStandBlockEntity) tileEntity).setCustomName(CraftChatMessage.fromStringOrNull(title)); + } +- return this.getInventory(tileEntity); ++ return this.getInventory(holder, type, tileEntity); // Paper + } + + @Override + public Inventory getInventory(Container tileEntity) { ++ // Paper start ++ return getInventory(null, null, tileEntity); ++ } ++ ++ @Override ++ public Inventory getInventory(InventoryHolder owner, InventoryType type, net.minecraft.world.Container tileEntity) { // Paper ++ if (owner != null) return new org.bukkit.craftbukkit.inventory.CraftInventoryCustom(owner, type, tileEntity); // Paper ++ // Paper end + return new CraftInventoryBrewer(tileEntity); + } + } diff --git a/patches/server/0444-Inventory-getHolder-method-without-block-snapshot.patch b/patches/server/0444-Inventory-getHolder-method-without-block-snapshot.patch index dca3e657db..9ed9fe0826 100644 --- a/patches/server/0444-Inventory-getHolder-method-without-block-snapshot.patch +++ b/patches/server/0444-Inventory-getHolder-method-without-block-snapshot.patch @@ -5,10 +5,10 @@ Subject: [PATCH] Inventory getHolder method without block snapshot diff --git a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -index 6ca8e76d1569f3f631275fea187e7110f09fc69e..7d8f29335d4c5188527cad66be39cedb34c26f50 100644 +index 3796f8b122ad981b6faacd2afcaf3696314aad6b..b17dab9e5c06d8789553b104602d7da35d926dd1 100644 --- a/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java +++ b/src/main/java/org/bukkit/craftbukkit/inventory/CraftInventory.java -@@ -528,6 +528,13 @@ public class CraftInventory implements Inventory { +@@ -532,6 +532,13 @@ public class CraftInventory implements Inventory { return this.inventory.getOwner(); }