diff --git a/paper-api/src/main/java/org/bukkit/inventory/MenuType.java b/paper-api/src/main/java/org/bukkit/inventory/MenuType.java index 2442361ce7..eb64a5ef29 100644 --- a/paper-api/src/main/java/org/bukkit/inventory/MenuType.java +++ b/paper-api/src/main/java/org/bukkit/inventory/MenuType.java @@ -1,5 +1,6 @@ package org.bukkit.inventory; +import net.kyori.adventure.text.Component; import org.bukkit.Keyed; import org.bukkit.NamespacedKey; import org.bukkit.Registry; @@ -18,12 +19,14 @@ import org.bukkit.inventory.view.builder.InventoryViewBuilder; import org.bukkit.inventory.view.builder.LocationInventoryViewBuilder; import org.bukkit.inventory.view.builder.MerchantInventoryViewBuilder; import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.NullMarked; +import org.jspecify.annotations.Nullable; /** * Represents different kinds of views, also known as menus, which can be * created and viewed by the player. */ +@NullMarked @ApiStatus.Experimental public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDependant { // Paper - make FeatureDependant @@ -138,6 +141,20 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe */ interface Typed<V extends InventoryView, B extends InventoryViewBuilder<V>> extends MenuType { + /** + * Creates a view of the specified menu type. + * <p> + * The player provided to create this view must be the player the view + * is opened for. See {@link HumanEntity#openInventory(InventoryView)} + * for more information. + * + * @param player the player the view belongs to + * @return the created {@link InventoryView} + */ + default V create(HumanEntity player) { + return create(player, (Component) null); + } + /** * Creates a view of the specified menu type. * <p> @@ -148,11 +165,10 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe * @param player the player the view belongs to * @param title the title of the view * @return the created {@link InventoryView} - * @deprecated Use {@link #create(HumanEntity, net.kyori.adventure.text.Component)} instead. + * @deprecated Use {@link #create(HumanEntity, Component)} instead. */ - @NotNull @Deprecated(since = "1.21") // Paper - adventure - V create(@NotNull HumanEntity player, @NotNull String title); + V create(HumanEntity player, @Nullable String title); // Paper start - adventure /** @@ -166,11 +182,9 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe * @param title the title of the view * @return the created {@link InventoryView} */ - @NotNull - V create(@NotNull HumanEntity player, @NotNull net.kyori.adventure.text.Component title); + V create(HumanEntity player, @Nullable Component title); // Paper end - adventure - @NotNull B builder(); } @@ -186,8 +200,7 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe * @param title the title of the view * @return the created {@link InventoryView} */ - @NotNull - InventoryView create(@NotNull HumanEntity player, @NotNull net.kyori.adventure.text.Component title); + InventoryView create(HumanEntity player, @Nullable Component title); // Paper end - adventure /** @@ -196,7 +209,6 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe * * @return the typed MenuType. */ - @NotNull MenuType.Typed<InventoryView, InventoryViewBuilder<InventoryView>> typed(); /** @@ -213,19 +225,16 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe * @throws IllegalArgumentException if the provided viewClass cannot be * typed to this MenuType */ - @NotNull - <V extends InventoryView, B extends InventoryViewBuilder<V>> MenuType.Typed<V, B> typed(@NotNull final Class<V> viewClass) throws IllegalArgumentException; + <V extends InventoryView, B extends InventoryViewBuilder<V>> MenuType.Typed<V, B> typed(final Class<V> viewClass) throws IllegalArgumentException; /** * Gets the {@link InventoryView} class of this MenuType. * * @return the {@link InventoryView} class of this MenuType */ - @NotNull Class<? extends InventoryView> getInventoryViewClass(); - @NotNull - private static <T extends MenuType> T get(@NotNull final String key) { + private static <T extends MenuType> T get(final String key) { return (T) Registry.MENU.getOrThrow(NamespacedKey.minecraft(key)); } } diff --git a/paper-api/src/main/java/org/bukkit/inventory/view/builder/InventoryViewBuilder.java b/paper-api/src/main/java/org/bukkit/inventory/view/builder/InventoryViewBuilder.java index 9f07522283..28e52e7da2 100644 --- a/paper-api/src/main/java/org/bukkit/inventory/view/builder/InventoryViewBuilder.java +++ b/paper-api/src/main/java/org/bukkit/inventory/view/builder/InventoryViewBuilder.java @@ -4,6 +4,7 @@ import net.kyori.adventure.text.Component; import org.bukkit.entity.HumanEntity; import org.bukkit.inventory.InventoryView; import org.jetbrains.annotations.ApiStatus; +import org.jspecify.annotations.Nullable; /** * Generic Builder for InventoryView's with no special attributes or parameters @@ -23,10 +24,10 @@ public interface InventoryViewBuilder<V extends InventoryView> { /** * Sets the title of the builder * - * @param title the title + * @param title the title, or null for a default title * @return this builder */ - InventoryViewBuilder<V> title(final Component title); + InventoryViewBuilder<V> title(@Nullable final Component title); /** * Builds this builder into a InventoryView diff --git a/paper-api/src/main/java/org/bukkit/inventory/view/builder/LocationInventoryViewBuilder.java b/paper-api/src/main/java/org/bukkit/inventory/view/builder/LocationInventoryViewBuilder.java index 9666aa3569..a532497277 100644 --- a/paper-api/src/main/java/org/bukkit/inventory/view/builder/LocationInventoryViewBuilder.java +++ b/paper-api/src/main/java/org/bukkit/inventory/view/builder/LocationInventoryViewBuilder.java @@ -4,7 +4,7 @@ import net.kyori.adventure.text.Component; import org.bukkit.Location; import org.bukkit.inventory.InventoryView; import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; /** * An InventoryViewBuilder that can be bound by location within the world @@ -18,7 +18,7 @@ public interface LocationInventoryViewBuilder<V extends InventoryView> extends I LocationInventoryViewBuilder<V> copy(); @Override - LocationInventoryViewBuilder<V> title(final @NotNull Component title); + LocationInventoryViewBuilder<V> title(final @Nullable Component title); /** * Determines whether or not the server should check if the player can reach diff --git a/paper-api/src/main/java/org/bukkit/inventory/view/builder/MerchantInventoryViewBuilder.java b/paper-api/src/main/java/org/bukkit/inventory/view/builder/MerchantInventoryViewBuilder.java index 76aecb54a9..a8e4e9f18f 100644 --- a/paper-api/src/main/java/org/bukkit/inventory/view/builder/MerchantInventoryViewBuilder.java +++ b/paper-api/src/main/java/org/bukkit/inventory/view/builder/MerchantInventoryViewBuilder.java @@ -5,7 +5,7 @@ import org.bukkit.Server; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.Merchant; import org.jetbrains.annotations.ApiStatus; -import org.jetbrains.annotations.NotNull; +import org.jspecify.annotations.Nullable; /** * An InventoryViewBuilder for creating merchant views @@ -19,7 +19,7 @@ public interface MerchantInventoryViewBuilder<V extends InventoryView> extends I MerchantInventoryViewBuilder<V> copy(); @Override - MerchantInventoryViewBuilder<V> title(final @NotNull Component title); + MerchantInventoryViewBuilder<V> title(final @Nullable Component title); /** * Adds a merchant to this builder diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch index 5ec5cd486d..7b27fcf641 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch @@ -9,8 +9,12 @@ @Nullable @Override public AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player player) { -@@ -106,7 +_,7 @@ - return (Component)(second.hasCustomName() ? second.getDisplayName() : Component.translatable("container.chestDouble")); +@@ -103,10 +_,10 @@ + if (first.hasCustomName()) { + return first.getDisplayName(); + } else { +- return (Component)(second.hasCustomName() ? second.getDisplayName() : Component.translatable("container.chestDouble")); ++ return (Component)(second.hasCustomName() ? second.getDisplayName() : Component.translatable("container.chestDouble")); // Paper - diff on change - CraftDoubleChestInventoryViewBuilder.defaultTitle } } - }); diff --git a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch index 32a967c2c3..b8ba6305b2 100644 --- a/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch +++ b/paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch @@ -37,3 +37,12 @@ protected ChestBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState blockState) { super(type, pos, blockState); } +@@ -71,7 +_,7 @@ + + @Override + protected Component getDefaultName() { +- return Component.translatable("container.chest"); ++ return Component.translatable("container.chest"); // Paper - diff on change - CraftStandardInventoryViewBuilder.defaultTitle + } + + @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java index cf5bcb0ebc..59eddee7e7 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java @@ -2479,7 +2479,7 @@ public final class CraftServer implements Server { @Override public @NotNull Merchant createMerchant() { - return new CraftMerchantCustom(net.kyori.adventure.text.Component.empty()); + return new CraftMerchantCustom(); } @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMenuType.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMenuType.java index 4c6cf43cee..326b62c859 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMenuType.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMenuType.java @@ -38,7 +38,7 @@ public class CraftMenuType<V extends InventoryView, B extends InventoryViewBuild @Override public V create(final HumanEntity player, final String title) { // Paper start - adventure - return builder().title(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(title)).build(player); + return builder().title(title != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(title) : null).build(player); } @Override public V create(final HumanEntity player, final net.kyori.adventure.text.Component title) { diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java index d9f9d4abae..3572e98f47 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java @@ -4,6 +4,7 @@ import com.google.common.base.Preconditions; import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.trading.Merchant; @@ -25,6 +26,11 @@ public class CraftMerchantCustom implements CraftMerchant { this.merchant = new MinecraftMerchant(title); getMerchant().craftMerchant = this; } + + public CraftMerchantCustom() { + this.merchant = new MinecraftMerchant(); + getMerchant().craftMerchant = this; + } // Paper end @Override @@ -54,6 +60,10 @@ public class CraftMerchantCustom implements CraftMerchant { Preconditions.checkArgument(title != null, "Title cannot be null"); this.title = io.papermc.paper.adventure.PaperAdventure.asVanilla(title); } + + public MinecraftMerchant() { + this.title = EntityType.VILLAGER.getDescription(); + } // Paper end @Override diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenus.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenus.java index 84c35792c4..0224aedbdf 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenus.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenus.java @@ -17,6 +17,7 @@ import net.minecraft.world.level.block.Blocks; import net.minecraft.world.level.block.entity.BeaconBlockEntity; import net.minecraft.world.level.block.entity.BlastFurnaceBlockEntity; import net.minecraft.world.level.block.entity.BrewingStandBlockEntity; +import net.minecraft.world.level.block.entity.ChestBlockEntity; import net.minecraft.world.level.block.entity.CrafterBlockEntity; import net.minecraft.world.level.block.entity.DispenserBlockEntity; import net.minecraft.world.level.block.entity.FurnaceBlockEntity; @@ -29,6 +30,7 @@ import org.bukkit.craftbukkit.inventory.CraftMerchant; import org.bukkit.craftbukkit.inventory.view.builder.CraftAccessLocationInventoryViewBuilder; import org.bukkit.craftbukkit.inventory.view.builder.CraftBlockEntityInventoryViewBuilder; import org.bukkit.craftbukkit.inventory.view.builder.CraftDoubleChestInventoryViewBuilder; +import org.bukkit.craftbukkit.inventory.view.builder.CraftEnchantmentInventoryViewBuilder; import org.bukkit.craftbukkit.inventory.view.builder.CraftMerchantInventoryViewBuilder; import org.bukkit.craftbukkit.inventory.view.builder.CraftStandardInventoryViewBuilder; import org.bukkit.inventory.InventoryView; @@ -87,7 +89,7 @@ public final class CraftMenus { return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftDoubleChestInventoryViewBuilder<>(handle))); } if (menuType == MenuType.GENERIC_9X3) { - return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.CHEST, null))); + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.CHEST, ChestBlockEntity::new, false))); } // this isn't ideal as both dispenser and dropper are 3x3, InventoryType can't currently handle generic 3x3s with size 9 // this needs to be removed when inventory creation is overhauled @@ -98,7 +100,7 @@ public final class CraftMenus { return asType(new MenuTypeData<>(CrafterView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.CRAFTER, CrafterBlockEntity::new))); } if (menuType == MenuType.ANVIL) { - return asType(new MenuTypeData<>(AnvilView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, AnvilMenu::new))); + return asType(new MenuTypeData<>(AnvilView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.ANVIL))); } if (menuType == MenuType.BEACON) { return asType(new MenuTypeData<>(BeaconView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.BEACON, BeaconBlockEntity::new))); @@ -110,16 +112,16 @@ public final class CraftMenus { return asType(new MenuTypeData<>(BrewingStandView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.BREWING_STAND, BrewingStandBlockEntity::new))); } if (menuType == MenuType.CRAFTING) { - return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, CraftingMenu::new))); + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.CRAFTING_TABLE))); } if (menuType == MenuType.ENCHANTMENT) { - return asType(new MenuTypeData<>(EnchantmentView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, EnchantmentMenu::new))); + return asType(new MenuTypeData<>(EnchantmentView.class, () -> new CraftEnchantmentInventoryViewBuilder(handle))); } if (menuType == MenuType.FURNACE) { return asType(new MenuTypeData<>(FurnaceView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.FURNACE, FurnaceBlockEntity::new))); } if (menuType == MenuType.GRINDSTONE) { - return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, GrindstoneMenu::new))); + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.GRINDSTONE))); } // We really don't need to be creating a tile entity for hopper but currently InventoryType doesn't have capacity // to understand otherwise @@ -131,7 +133,7 @@ public final class CraftMenus { return asType(new MenuTypeData<>(LecternView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.LECTERN, LecternBlockEntity::new))); } if (menuType == MenuType.LOOM) { - return asType(new MenuTypeData<>(LoomView.class, () -> new CraftStandardInventoryViewBuilder<>(handle))); + return asType(new MenuTypeData<>(LoomView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.LOOM))); } if (menuType == MenuType.MERCHANT) { return asType(new MenuTypeData<>(MerchantView.class, () -> new CraftMerchantInventoryViewBuilder<>(handle))); @@ -140,16 +142,16 @@ public final class CraftMenus { return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.SHULKER_BOX, ShulkerBoxBlockEntity::new))); } if (menuType == MenuType.SMITHING) { - return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, SmithingMenu::new))); + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.SMITHING_TABLE))); } if (menuType == MenuType.SMOKER) { return asType(new MenuTypeData<>(FurnaceView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.SMOKER, SmokerBlockEntity::new))); } if (menuType == MenuType.CARTOGRAPHY_TABLE) { - return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, CartographyTableMenu::new))); + return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.CARTOGRAPHY_TABLE))); } if (menuType == MenuType.STONECUTTER) { - return asType(new MenuTypeData<>(StonecutterView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, StonecutterMenu::new))); + return asType(new MenuTypeData<>(StonecutterView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.STONECUTTER))); } return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftStandardInventoryViewBuilder<>(handle))); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractInventoryViewBuilder.java index 185ad0fc16..ef1abf7bfa 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractInventoryViewBuilder.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractInventoryViewBuilder.java @@ -10,21 +10,22 @@ import org.bukkit.craftbukkit.entity.CraftHumanEntity; import org.bukkit.entity.HumanEntity; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.view.builder.InventoryViewBuilder; -import org.checkerframework.checker.nullness.qual.MonotonicNonNull; +import org.jspecify.annotations.Nullable; public abstract class CraftAbstractInventoryViewBuilder<V extends InventoryView> implements InventoryViewBuilder<V> { protected final MenuType<?> handle; protected boolean checkReachable = false; - protected @MonotonicNonNull Component title = null; + protected @Nullable Component title = null; + protected net.minecraft.network.chat.Component defaultTitle = null; public CraftAbstractInventoryViewBuilder(final MenuType<?> handle) { this.handle = handle; } @Override - public InventoryViewBuilder<V> title(final Component title) { + public InventoryViewBuilder<V> title(final @Nullable Component title) { this.title = title; return this; } @@ -33,14 +34,14 @@ public abstract class CraftAbstractInventoryViewBuilder<V extends InventoryView> @Override public V build(final HumanEntity player) { Preconditions.checkArgument(player != null, "The given player must not be null"); - Preconditions.checkArgument(this.title != null, "The given title must not be null"); Preconditions.checkArgument(player instanceof CraftHumanEntity, "The given player must be a CraftHumanEntity"); final CraftHumanEntity craftHuman = (CraftHumanEntity) player; - Preconditions.checkArgument(craftHuman.getHandle() instanceof ServerPlayer, "The given player must be an EntityPlayer"); + Preconditions.checkArgument(craftHuman.getHandle() instanceof ServerPlayer, "The given player must be an ServerPlayer"); final ServerPlayer serverPlayer = (ServerPlayer) craftHuman.getHandle(); + final AbstractContainerMenu container = buildContainer(serverPlayer); container.checkReachable = this.checkReachable; - container.setTitle(PaperAdventure.asVanilla(this.title)); + container.setTitle(this.title != null ? PaperAdventure.asVanilla(this.title) : this.defaultTitle); return (V) container.getBukkitView(); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractLocationInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractLocationInventoryViewBuilder.java index 7a894ca078..15f1b30160 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractLocationInventoryViewBuilder.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractLocationInventoryViewBuilder.java @@ -22,7 +22,7 @@ public abstract class CraftAbstractLocationInventoryViewBuilder<V extends Invent } @Override - public LocationInventoryViewBuilder<V> title(final Component title) { + public LocationInventoryViewBuilder<V> title(final @Nullable Component title) { return (LocationInventoryViewBuilder<V>) super.title(title); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAccessLocationInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAccessLocationInventoryViewBuilder.java index 096f3ebf81..8e0d453199 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAccessLocationInventoryViewBuilder.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAccessLocationInventoryViewBuilder.java @@ -1,37 +1,50 @@ package org.bukkit.craftbukkit.inventory.view.builder; +import net.minecraft.core.BlockPos; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.MenuProvider; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.ContainerLevelAccess; import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockState; import org.bukkit.inventory.InventoryView; import org.bukkit.inventory.view.builder.LocationInventoryViewBuilder; public class CraftAccessLocationInventoryViewBuilder<V extends InventoryView> extends CraftAbstractLocationInventoryViewBuilder<V> { - private final CraftAccessContainerObjectBuilder containerBuilder; + private final Block block; - public CraftAccessLocationInventoryViewBuilder(final MenuType<?> handle, final CraftAccessContainerObjectBuilder containerBuilder) { + public CraftAccessLocationInventoryViewBuilder(final MenuType<?> handle, final Block block) { super(handle); - this.containerBuilder = containerBuilder; + this.block = block; } @Override protected AbstractContainerMenu buildContainer(final ServerPlayer player) { - final ContainerLevelAccess access; - if (super.position == null) { - access = ContainerLevelAccess.create(player.level(), player.blockPosition()); + final BlockState effectiveBlockState; + final BlockPos effectiveBlockPos; + final Level effectiveLevel; + if (super.position != null) { + effectiveBlockPos = super.position; + effectiveLevel = super.world; + effectiveBlockState = super.world.getBlockState(position); } else { - access = ContainerLevelAccess.create(super.world, super.position); + effectiveBlockPos = player.blockPosition(); + effectiveLevel = player.level(); + effectiveBlockState = block.defaultBlockState(); } - return this.containerBuilder.build(player.nextContainerCounter(), player.getInventory(), access); + final MenuProvider provider = block.getMenuProvider(effectiveBlockState, effectiveLevel, effectiveBlockPos); + super.defaultTitle = provider.getDisplayName(); + return provider.createMenu(player.nextContainerCounter(), player.getInventory(), player); } @Override public LocationInventoryViewBuilder<V> copy() { - final CraftAccessLocationInventoryViewBuilder<V> copy = new CraftAccessLocationInventoryViewBuilder<>(this.handle, this.containerBuilder); + final CraftAccessLocationInventoryViewBuilder<V> copy = new CraftAccessLocationInventoryViewBuilder<>(this.handle, this.block); copy.world = super.world; copy.position = super.position; copy.checkReachable = super.checkReachable; diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftBlockEntityInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftBlockEntityInventoryViewBuilder.java index 2625814440..b555d5078d 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftBlockEntityInventoryViewBuilder.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftBlockEntityInventoryViewBuilder.java @@ -16,10 +16,25 @@ import org.jspecify.annotations.Nullable; public class CraftBlockEntityInventoryViewBuilder<V extends InventoryView> extends CraftAbstractLocationInventoryViewBuilder<V> { private final Block block; - private final @Nullable CraftTileInventoryBuilder builder; + private final boolean useFakeBlockEntity; + private final @Nullable CraftBlockInventoryBuilder builder; - public CraftBlockEntityInventoryViewBuilder(final MenuType<?> handle, final Block block, final @Nullable CraftTileInventoryBuilder builder) { + public CraftBlockEntityInventoryViewBuilder( + final MenuType<?> handle, + final Block block, + final @Nullable CraftBlockInventoryBuilder builder + ) { + this(handle, block, builder, true); + } + + public CraftBlockEntityInventoryViewBuilder( + final MenuType<?> handle, + final Block block, + final @Nullable CraftBlockInventoryBuilder builder, + final boolean useFakeBlockEntity + ) { super(handle); + this.useFakeBlockEntity = useFakeBlockEntity; this.block = block; this.builder = builder; } @@ -32,35 +47,44 @@ public class CraftBlockEntityInventoryViewBuilder<V extends InventoryView> exten if (this.position == null) { this.position = player.blockPosition(); + return buildFakeBlockEntity(player); } final BlockEntity entity = this.world.getBlockEntity(position); if (!(entity instanceof final MenuConstructor container)) { - return buildFakeTile(player); + return buildFakeBlockEntity(player); } final AbstractContainerMenu atBlock = container.createMenu(player.nextContainerCounter(), player.getInventory(), player); if (atBlock.getType() != super.handle) { - return buildFakeTile(player); + return buildFakeBlockEntity(player); } + if (!(entity instanceof final MenuProvider provider)) { + throw new IllegalStateException("Provided blockEntity during MenuType creation can not find a default title! This is a bug!"); + } + + super.defaultTitle = provider.getDisplayName(); return atBlock; } - private AbstractContainerMenu buildFakeTile(final ServerPlayer player) { - if (this.builder == null) { + private AbstractContainerMenu buildFakeBlockEntity(final ServerPlayer player) { + final MenuProvider inventory = this.builder.build(this.position, this.block.defaultBlockState()); + if (inventory instanceof final BlockEntity blockEntity) { + blockEntity.setLevel(this.world); + super.defaultTitle = inventory.getDisplayName(); + } + + if (!this.useFakeBlockEntity) { // gets around open noise for chest return handle.create(player.nextContainerCounter(), player.getInventory()); } - final MenuProvider inventory = this.builder.build(this.position, this.block.defaultBlockState()); - if (inventory instanceof final BlockEntity tile) { - tile.setLevel(this.world); - } + return inventory.createMenu(player.nextContainerCounter(), player.getInventory(), player); } @Override public LocationInventoryViewBuilder<V> copy() { - final CraftBlockEntityInventoryViewBuilder<V> copy = new CraftBlockEntityInventoryViewBuilder<>(super.handle, this.block, this.builder); + final CraftBlockEntityInventoryViewBuilder<V> copy = new CraftBlockEntityInventoryViewBuilder<>(super.handle, this.block, this.builder, this.useFakeBlockEntity); copy.world = this.world; copy.position = this.position; copy.checkReachable = super.checkReachable; @@ -68,7 +92,7 @@ public class CraftBlockEntityInventoryViewBuilder<V extends InventoryView> exten return copy; } - public interface CraftTileInventoryBuilder { + public interface CraftBlockInventoryBuilder { MenuProvider build(BlockPos blockPosition, BlockState blockData); } } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftDoubleChestInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftDoubleChestInventoryViewBuilder.java index 331e3797a5..f0133272dd 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftDoubleChestInventoryViewBuilder.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftDoubleChestInventoryViewBuilder.java @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit.inventory.view.builder; +import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.MenuProvider; import net.minecraft.world.inventory.AbstractContainerMenu; @@ -15,6 +16,7 @@ public class CraftDoubleChestInventoryViewBuilder<V extends InventoryView> exten public CraftDoubleChestInventoryViewBuilder(final MenuType<?> handle) { super(handle); + super.defaultTitle = Component.translatable("container.chestDouble"); } @Override @@ -24,7 +26,9 @@ public class CraftDoubleChestInventoryViewBuilder<V extends InventoryView> exten } final ChestBlock chest = (ChestBlock) Blocks.CHEST; - final DoubleBlockCombiner.NeighborCombineResult<? extends ChestBlockEntity> result = chest.combine(super.world.getBlockState(super.position), super.world, super.position, false); + final DoubleBlockCombiner.NeighborCombineResult<? extends ChestBlockEntity> result = chest.combine( + super.world.getBlockState(super.position), super.world, super.position, false + ); if (result instanceof DoubleBlockCombiner.NeighborCombineResult.Single<? extends ChestBlockEntity>) { return handle.create(player.nextContainerCounter(), player.getInventory()); } @@ -33,6 +37,7 @@ public class CraftDoubleChestInventoryViewBuilder<V extends InventoryView> exten if (combined == null) { return handle.create(player.nextContainerCounter(), player.getInventory()); } + return combined.createMenu(player.nextContainerCounter(), player.getInventory(), player); } diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftEnchantmentInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftEnchantmentInventoryViewBuilder.java new file mode 100644 index 0000000000..6f50294159 --- /dev/null +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftEnchantmentInventoryViewBuilder.java @@ -0,0 +1,40 @@ +package org.bukkit.craftbukkit.inventory.view.builder; + +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.inventory.EnchantmentMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.EnchantingTableBlockEntity; +import org.bukkit.inventory.view.EnchantmentView; + +public class CraftEnchantmentInventoryViewBuilder extends CraftAbstractLocationInventoryViewBuilder<EnchantmentView> { + + public CraftEnchantmentInventoryViewBuilder(final MenuType<?> handle) { + super(handle); + } + + @Override + protected AbstractContainerMenu buildContainer(final ServerPlayer player) { + if (this.world == null) { + this.world = player.level(); + } + + if (this.position == null) { + this.position = player.blockPosition(); + super.defaultTitle = new EnchantingTableBlockEntity(this.position, Blocks.ENCHANTING_TABLE.defaultBlockState()).getDisplayName(); + return new EnchantmentMenu(player.nextContainerCounter(), player.getInventory(), ContainerLevelAccess.create(this.world, this.position)); + } + + final BlockEntity entity = this.world.getBlockEntity(position); + if (entity instanceof final EnchantingTableBlockEntity enchantingBlockEntity) { + super.defaultTitle = enchantingBlockEntity.getDisplayName(); + } else { + super.defaultTitle = new EnchantingTableBlockEntity(this.position, Blocks.ENCHANTING_TABLE.defaultBlockState()).getDisplayName(); + } + + return new EnchantmentMenu(player.nextContainerCounter(), player.getInventory(), ContainerLevelAccess.create(this.world, this.position)); + } +} diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftMerchantInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftMerchantInventoryViewBuilder.java index 7f7518aa73..d46f942e1c 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftMerchantInventoryViewBuilder.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftMerchantInventoryViewBuilder.java @@ -4,6 +4,7 @@ import com.google.common.base.Preconditions; import io.papermc.paper.adventure.PaperAdventure; import net.kyori.adventure.text.Component; import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.npc.AbstractVillager; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.MenuType; import net.minecraft.world.inventory.MerchantMenu; @@ -25,7 +26,7 @@ public class CraftMerchantInventoryViewBuilder<V extends InventoryView> extends } @Override - public MerchantInventoryViewBuilder<V> title(final Component title) { + public MerchantInventoryViewBuilder<V> title(final @Nullable Component title) { return (MerchantInventoryViewBuilder<V>) super.title(title); } @@ -44,24 +45,34 @@ public class CraftMerchantInventoryViewBuilder<V extends InventoryView> extends @Override public V build(final HumanEntity player) { Preconditions.checkArgument(player != null, "The given player must not be null"); - Preconditions.checkArgument(this.title != null, "The given title must not be null"); Preconditions.checkArgument(player instanceof CraftHumanEntity, "The given player must be a CraftHumanEntity"); final CraftHumanEntity craftHuman = (CraftHumanEntity) player; - Preconditions.checkArgument(craftHuman.getHandle() instanceof ServerPlayer, "The given player must be an EntityPlayer"); + Preconditions.checkArgument(craftHuman.getHandle() instanceof ServerPlayer, "The given player must be an ServerPlayer"); final ServerPlayer serverPlayer = (ServerPlayer) craftHuman.getHandle(); final MerchantMenu container; if (this.merchant == null) { - container = new MerchantMenu(serverPlayer.nextContainerCounter(), serverPlayer.getInventory(), new CraftMerchantCustom(title).getMerchant()); - } else { - container = new MerchantMenu(serverPlayer.nextContainerCounter(), serverPlayer.getInventory(), this.merchant); + this.merchant = this.title == null ? new CraftMerchantCustom().getMerchant() : new CraftMerchantCustom(title).getMerchant(); } + container = new MerchantMenu(serverPlayer.nextContainerCounter(), serverPlayer.getInventory(), this.merchant); + container.checkReachable = super.checkReachable; - container.setTitle(PaperAdventure.asVanilla(this.title)); + setDefaultTitle(this.merchant); + container.setTitle(super.title != null ? PaperAdventure.asVanilla(this.title) : super.defaultTitle); return (V) container.getBukkitView(); } + private void setDefaultTitle(final net.minecraft.world.item.trading.Merchant merchant) { + if (merchant instanceof final AbstractVillager villager) { + super.defaultTitle = villager.getDisplayName(); + } else if (merchant instanceof final CraftMerchantCustom.MinecraftMerchant custom) { + super.defaultTitle = custom.getScoreboardDisplayName(); + } else { + throw new IllegalStateException("Provided merchant during MenuType creation can not find a default title! This is a bug!"); + } + } + @Override protected AbstractContainerMenu buildContainer(final ServerPlayer player) { throw new UnsupportedOperationException("buildContainer is not supported for CraftMerchantInventoryViewBuilder"); diff --git a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftStandardInventoryViewBuilder.java b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftStandardInventoryViewBuilder.java index e528facbe0..670f79d008 100644 --- a/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftStandardInventoryViewBuilder.java +++ b/paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftStandardInventoryViewBuilder.java @@ -1,5 +1,6 @@ package org.bukkit.craftbukkit.inventory.view.builder; +import net.minecraft.network.chat.Component; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.inventory.MenuType; @@ -10,6 +11,7 @@ public class CraftStandardInventoryViewBuilder<V extends InventoryView> extends public CraftStandardInventoryViewBuilder(final MenuType<?> handle) { super(handle); + super.defaultTitle = Component.translatable("container.chest"); } @Override