Skip to content

Commit 8eb8e44

Browse files
authored
Allow For Default Titles in InventoryView Builders (#12013)
1 parent 84609dc commit 8eb8e44

18 files changed

+201
-70
lines changed

paper-api/src/main/java/org/bukkit/inventory/MenuType.java

Lines changed: 24 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package org.bukkit.inventory;
22

3+
import net.kyori.adventure.text.Component;
34
import org.bukkit.Keyed;
45
import org.bukkit.NamespacedKey;
56
import org.bukkit.Registry;
@@ -18,12 +19,14 @@
1819
import org.bukkit.inventory.view.builder.LocationInventoryViewBuilder;
1920
import org.bukkit.inventory.view.builder.MerchantInventoryViewBuilder;
2021
import org.jetbrains.annotations.ApiStatus;
21-
import org.jetbrains.annotations.NotNull;
22+
import org.jspecify.annotations.NullMarked;
23+
import org.jspecify.annotations.Nullable;
2224

2325
/**
2426
* Represents different kinds of views, also known as menus, which can be
2527
* created and viewed by the player.
2628
*/
29+
@NullMarked
2730
@ApiStatus.Experimental
2831
public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDependant { // Paper - make FeatureDependant
2932

@@ -138,6 +141,20 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe
138141
*/
139142
interface Typed<V extends InventoryView, B extends InventoryViewBuilder<V>> extends MenuType {
140143

144+
/**
145+
* Creates a view of the specified menu type.
146+
* <p>
147+
* The player provided to create this view must be the player the view
148+
* is opened for. See {@link HumanEntity#openInventory(InventoryView)}
149+
* for more information.
150+
*
151+
* @param player the player the view belongs to
152+
* @return the created {@link InventoryView}
153+
*/
154+
default V create(HumanEntity player) {
155+
return create(player, (Component) null);
156+
}
157+
141158
/**
142159
* Creates a view of the specified menu type.
143160
* <p>
@@ -148,11 +165,10 @@ interface Typed<V extends InventoryView, B extends InventoryViewBuilder<V>> exte
148165
* @param player the player the view belongs to
149166
* @param title the title of the view
150167
* @return the created {@link InventoryView}
151-
* @deprecated Use {@link #create(HumanEntity, net.kyori.adventure.text.Component)} instead.
168+
* @deprecated Use {@link #create(HumanEntity, Component)} instead.
152169
*/
153-
@NotNull
154170
@Deprecated(since = "1.21") // Paper - adventure
155-
V create(@NotNull HumanEntity player, @NotNull String title);
171+
V create(HumanEntity player, @Nullable String title);
156172

157173
// Paper start - adventure
158174
/**
@@ -166,11 +182,9 @@ interface Typed<V extends InventoryView, B extends InventoryViewBuilder<V>> exte
166182
* @param title the title of the view
167183
* @return the created {@link InventoryView}
168184
*/
169-
@NotNull
170-
V create(@NotNull HumanEntity player, @NotNull net.kyori.adventure.text.Component title);
185+
V create(HumanEntity player, @Nullable Component title);
171186
// Paper end - adventure
172187

173-
@NotNull
174188
B builder();
175189
}
176190

@@ -186,8 +200,7 @@ interface Typed<V extends InventoryView, B extends InventoryViewBuilder<V>> exte
186200
* @param title the title of the view
187201
* @return the created {@link InventoryView}
188202
*/
189-
@NotNull
190-
InventoryView create(@NotNull HumanEntity player, @NotNull net.kyori.adventure.text.Component title);
203+
InventoryView create(HumanEntity player, @Nullable Component title);
191204
// Paper end - adventure
192205

193206
/**
@@ -196,7 +209,6 @@ interface Typed<V extends InventoryView, B extends InventoryViewBuilder<V>> exte
196209
*
197210
* @return the typed MenuType.
198211
*/
199-
@NotNull
200212
MenuType.Typed<InventoryView, InventoryViewBuilder<InventoryView>> typed();
201213

202214
/**
@@ -213,19 +225,16 @@ interface Typed<V extends InventoryView, B extends InventoryViewBuilder<V>> exte
213225
* @throws IllegalArgumentException if the provided viewClass cannot be
214226
* typed to this MenuType
215227
*/
216-
@NotNull
217-
<V extends InventoryView, B extends InventoryViewBuilder<V>> MenuType.Typed<V, B> typed(@NotNull final Class<V> viewClass) throws IllegalArgumentException;
228+
<V extends InventoryView, B extends InventoryViewBuilder<V>> MenuType.Typed<V, B> typed(final Class<V> viewClass) throws IllegalArgumentException;
218229

219230
/**
220231
* Gets the {@link InventoryView} class of this MenuType.
221232
*
222233
* @return the {@link InventoryView} class of this MenuType
223234
*/
224-
@NotNull
225235
Class<? extends InventoryView> getInventoryViewClass();
226236

227-
@NotNull
228-
private static <T extends MenuType> T get(@NotNull final String key) {
237+
private static <T extends MenuType> T get(final String key) {
229238
return (T) Registry.MENU.getOrThrow(NamespacedKey.minecraft(key));
230239
}
231240
}

paper-api/src/main/java/org/bukkit/inventory/view/builder/InventoryViewBuilder.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import org.bukkit.entity.HumanEntity;
55
import org.bukkit.inventory.InventoryView;
66
import org.jetbrains.annotations.ApiStatus;
7+
import org.jspecify.annotations.Nullable;
78

89
/**
910
* Generic Builder for InventoryView's with no special attributes or parameters
@@ -23,10 +24,10 @@ public interface InventoryViewBuilder<V extends InventoryView> {
2324
/**
2425
* Sets the title of the builder
2526
*
26-
* @param title the title
27+
* @param title the title, or null for a default title
2728
* @return this builder
2829
*/
29-
InventoryViewBuilder<V> title(final Component title);
30+
InventoryViewBuilder<V> title(@Nullable final Component title);
3031

3132
/**
3233
* Builds this builder into a InventoryView

paper-api/src/main/java/org/bukkit/inventory/view/builder/LocationInventoryViewBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import org.bukkit.Location;
55
import org.bukkit.inventory.InventoryView;
66
import org.jetbrains.annotations.ApiStatus;
7-
import org.jetbrains.annotations.NotNull;
7+
import org.jspecify.annotations.Nullable;
88

99
/**
1010
* An InventoryViewBuilder that can be bound by location within the world
@@ -18,7 +18,7 @@ public interface LocationInventoryViewBuilder<V extends InventoryView> extends I
1818
LocationInventoryViewBuilder<V> copy();
1919

2020
@Override
21-
LocationInventoryViewBuilder<V> title(final @NotNull Component title);
21+
LocationInventoryViewBuilder<V> title(final @Nullable Component title);
2222

2323
/**
2424
* Determines whether or not the server should check if the player can reach

paper-api/src/main/java/org/bukkit/inventory/view/builder/MerchantInventoryViewBuilder.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import org.bukkit.inventory.InventoryView;
66
import org.bukkit.inventory.Merchant;
77
import org.jetbrains.annotations.ApiStatus;
8-
import org.jetbrains.annotations.NotNull;
8+
import org.jspecify.annotations.Nullable;
99

1010
/**
1111
* An InventoryViewBuilder for creating merchant views
@@ -19,7 +19,7 @@ public interface MerchantInventoryViewBuilder<V extends InventoryView> extends I
1919
MerchantInventoryViewBuilder<V> copy();
2020

2121
@Override
22-
MerchantInventoryViewBuilder<V> title(final @NotNull Component title);
22+
MerchantInventoryViewBuilder<V> title(final @Nullable Component title);
2323

2424
/**
2525
* Adds a merchant to this builder

paper-server/patches/sources/net/minecraft/world/level/block/ChestBlock.java.patch

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,12 @@
99
@Nullable
1010
@Override
1111
public AbstractContainerMenu createMenu(int containerId, Inventory playerInventory, Player player) {
12-
@@ -106,7 +_,7 @@
13-
return (Component)(second.hasCustomName() ? second.getDisplayName() : Component.translatable("container.chestDouble"));
12+
@@ -103,10 +_,10 @@
13+
if (first.hasCustomName()) {
14+
return first.getDisplayName();
15+
} else {
16+
- return (Component)(second.hasCustomName() ? second.getDisplayName() : Component.translatable("container.chestDouble"));
17+
+ return (Component)(second.hasCustomName() ? second.getDisplayName() : Component.translatable("container.chestDouble")); // Paper - diff on change - CraftDoubleChestInventoryViewBuilder.defaultTitle
1418
}
1519
}
1620
- });

paper-server/patches/sources/net/minecraft/world/level/block/entity/ChestBlockEntity.java.patch

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,12 @@
3737
protected ChestBlockEntity(BlockEntityType<?> type, BlockPos pos, BlockState blockState) {
3838
super(type, pos, blockState);
3939
}
40+
@@ -71,7 +_,7 @@
41+
42+
@Override
43+
protected Component getDefaultName() {
44+
- return Component.translatable("container.chest");
45+
+ return Component.translatable("container.chest"); // Paper - diff on change - CraftStandardInventoryViewBuilder.defaultTitle
46+
}
47+
48+
@Override

paper-server/src/main/java/org/bukkit/craftbukkit/CraftServer.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2479,7 +2479,7 @@ public Merchant createMerchant(String title) {
24792479

24802480
@Override
24812481
public @NotNull Merchant createMerchant() {
2482-
return new CraftMerchantCustom(net.kyori.adventure.text.Component.empty());
2482+
return new CraftMerchantCustom();
24832483
}
24842484

24852485
@Override

paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMenuType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public net.minecraft.world.inventory.MenuType<?> getHandle() {
3838
@Override
3939
public V create(final HumanEntity player, final String title) {
4040
// Paper start - adventure
41-
return builder().title(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(title)).build(player);
41+
return builder().title(title != null ? net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(title) : null).build(player);
4242
}
4343
@Override
4444
public V create(final HumanEntity player, final net.kyori.adventure.text.Component title) {

paper-server/src/main/java/org/bukkit/craftbukkit/inventory/CraftMerchantCustom.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import net.minecraft.network.chat.Component;
55
import net.minecraft.sounds.SoundEvent;
66
import net.minecraft.sounds.SoundEvents;
7+
import net.minecraft.world.entity.EntityType;
78
import net.minecraft.world.entity.player.Player;
89
import net.minecraft.world.item.ItemStack;
910
import net.minecraft.world.item.trading.Merchant;
@@ -25,6 +26,11 @@ public CraftMerchantCustom(net.kyori.adventure.text.Component title) {
2526
this.merchant = new MinecraftMerchant(title);
2627
getMerchant().craftMerchant = this;
2728
}
29+
30+
public CraftMerchantCustom() {
31+
this.merchant = new MinecraftMerchant();
32+
getMerchant().craftMerchant = this;
33+
}
2834
// Paper end
2935

3036
@Override
@@ -54,6 +60,10 @@ public MinecraftMerchant(net.kyori.adventure.text.Component title) {
5460
Preconditions.checkArgument(title != null, "Title cannot be null");
5561
this.title = io.papermc.paper.adventure.PaperAdventure.asVanilla(title);
5662
}
63+
64+
public MinecraftMerchant() {
65+
this.title = EntityType.VILLAGER.getDescription();
66+
}
5767
// Paper end
5868

5969
@Override

paper-server/src/main/java/org/bukkit/craftbukkit/inventory/util/CraftMenus.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import net.minecraft.world.level.block.entity.BeaconBlockEntity;
1818
import net.minecraft.world.level.block.entity.BlastFurnaceBlockEntity;
1919
import net.minecraft.world.level.block.entity.BrewingStandBlockEntity;
20+
import net.minecraft.world.level.block.entity.ChestBlockEntity;
2021
import net.minecraft.world.level.block.entity.CrafterBlockEntity;
2122
import net.minecraft.world.level.block.entity.DispenserBlockEntity;
2223
import net.minecraft.world.level.block.entity.FurnaceBlockEntity;
@@ -29,6 +30,7 @@
2930
import org.bukkit.craftbukkit.inventory.view.builder.CraftAccessLocationInventoryViewBuilder;
3031
import org.bukkit.craftbukkit.inventory.view.builder.CraftBlockEntityInventoryViewBuilder;
3132
import org.bukkit.craftbukkit.inventory.view.builder.CraftDoubleChestInventoryViewBuilder;
33+
import org.bukkit.craftbukkit.inventory.view.builder.CraftEnchantmentInventoryViewBuilder;
3234
import org.bukkit.craftbukkit.inventory.view.builder.CraftMerchantInventoryViewBuilder;
3335
import org.bukkit.craftbukkit.inventory.view.builder.CraftStandardInventoryViewBuilder;
3436
import org.bukkit.inventory.InventoryView;
@@ -87,7 +89,7 @@ public static <V extends InventoryView, B extends InventoryViewBuilder<V>> MenuT
8789
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftDoubleChestInventoryViewBuilder<>(handle)));
8890
}
8991
if (menuType == MenuType.GENERIC_9X3) {
90-
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.CHEST, null)));
92+
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.CHEST, ChestBlockEntity::new, false)));
9193
}
9294
// this isn't ideal as both dispenser and dropper are 3x3, InventoryType can't currently handle generic 3x3s with size 9
9395
// this needs to be removed when inventory creation is overhauled
@@ -98,7 +100,7 @@ public static <V extends InventoryView, B extends InventoryViewBuilder<V>> MenuT
98100
return asType(new MenuTypeData<>(CrafterView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.CRAFTER, CrafterBlockEntity::new)));
99101
}
100102
if (menuType == MenuType.ANVIL) {
101-
return asType(new MenuTypeData<>(AnvilView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, AnvilMenu::new)));
103+
return asType(new MenuTypeData<>(AnvilView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.ANVIL)));
102104
}
103105
if (menuType == MenuType.BEACON) {
104106
return asType(new MenuTypeData<>(BeaconView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.BEACON, BeaconBlockEntity::new)));
@@ -110,16 +112,16 @@ public static <V extends InventoryView, B extends InventoryViewBuilder<V>> MenuT
110112
return asType(new MenuTypeData<>(BrewingStandView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.BREWING_STAND, BrewingStandBlockEntity::new)));
111113
}
112114
if (menuType == MenuType.CRAFTING) {
113-
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, CraftingMenu::new)));
115+
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.CRAFTING_TABLE)));
114116
}
115117
if (menuType == MenuType.ENCHANTMENT) {
116-
return asType(new MenuTypeData<>(EnchantmentView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, EnchantmentMenu::new)));
118+
return asType(new MenuTypeData<>(EnchantmentView.class, () -> new CraftEnchantmentInventoryViewBuilder(handle)));
117119
}
118120
if (menuType == MenuType.FURNACE) {
119121
return asType(new MenuTypeData<>(FurnaceView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.FURNACE, FurnaceBlockEntity::new)));
120122
}
121123
if (menuType == MenuType.GRINDSTONE) {
122-
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, GrindstoneMenu::new)));
124+
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.GRINDSTONE)));
123125
}
124126
// We really don't need to be creating a tile entity for hopper but currently InventoryType doesn't have capacity
125127
// to understand otherwise
@@ -131,7 +133,7 @@ public static <V extends InventoryView, B extends InventoryViewBuilder<V>> MenuT
131133
return asType(new MenuTypeData<>(LecternView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.LECTERN, LecternBlockEntity::new)));
132134
}
133135
if (menuType == MenuType.LOOM) {
134-
return asType(new MenuTypeData<>(LoomView.class, () -> new CraftStandardInventoryViewBuilder<>(handle)));
136+
return asType(new MenuTypeData<>(LoomView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.LOOM)));
135137
}
136138
if (menuType == MenuType.MERCHANT) {
137139
return asType(new MenuTypeData<>(MerchantView.class, () -> new CraftMerchantInventoryViewBuilder<>(handle)));
@@ -140,16 +142,16 @@ public static <V extends InventoryView, B extends InventoryViewBuilder<V>> MenuT
140142
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.SHULKER_BOX, ShulkerBoxBlockEntity::new)));
141143
}
142144
if (menuType == MenuType.SMITHING) {
143-
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, SmithingMenu::new)));
145+
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.SMITHING_TABLE)));
144146
}
145147
if (menuType == MenuType.SMOKER) {
146148
return asType(new MenuTypeData<>(FurnaceView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.SMOKER, SmokerBlockEntity::new)));
147149
}
148150
if (menuType == MenuType.CARTOGRAPHY_TABLE) {
149-
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, CartographyTableMenu::new)));
151+
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.CARTOGRAPHY_TABLE)));
150152
}
151153
if (menuType == MenuType.STONECUTTER) {
152-
return asType(new MenuTypeData<>(StonecutterView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, StonecutterMenu::new)));
154+
return asType(new MenuTypeData<>(StonecutterView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, Blocks.STONECUTTER)));
153155
}
154156

155157
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftStandardInventoryViewBuilder<>(handle)));

paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractInventoryViewBuilder.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,22 @@
1010
import org.bukkit.entity.HumanEntity;
1111
import org.bukkit.inventory.InventoryView;
1212
import org.bukkit.inventory.view.builder.InventoryViewBuilder;
13-
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
13+
import org.jspecify.annotations.Nullable;
1414

1515
public abstract class CraftAbstractInventoryViewBuilder<V extends InventoryView> implements InventoryViewBuilder<V> {
1616

1717
protected final MenuType<?> handle;
1818

1919
protected boolean checkReachable = false;
20-
protected @MonotonicNonNull Component title = null;
20+
protected @Nullable Component title = null;
21+
protected net.minecraft.network.chat.Component defaultTitle = null;
2122

2223
public CraftAbstractInventoryViewBuilder(final MenuType<?> handle) {
2324
this.handle = handle;
2425
}
2526

2627
@Override
27-
public InventoryViewBuilder<V> title(final Component title) {
28+
public InventoryViewBuilder<V> title(final @Nullable Component title) {
2829
this.title = title;
2930
return this;
3031
}
@@ -33,14 +34,14 @@ public InventoryViewBuilder<V> title(final Component title) {
3334
@Override
3435
public V build(final HumanEntity player) {
3536
Preconditions.checkArgument(player != null, "The given player must not be null");
36-
Preconditions.checkArgument(this.title != null, "The given title must not be null");
3737
Preconditions.checkArgument(player instanceof CraftHumanEntity, "The given player must be a CraftHumanEntity");
3838
final CraftHumanEntity craftHuman = (CraftHumanEntity) player;
39-
Preconditions.checkArgument(craftHuman.getHandle() instanceof ServerPlayer, "The given player must be an EntityPlayer");
39+
Preconditions.checkArgument(craftHuman.getHandle() instanceof ServerPlayer, "The given player must be an ServerPlayer");
4040
final ServerPlayer serverPlayer = (ServerPlayer) craftHuman.getHandle();
41+
4142
final AbstractContainerMenu container = buildContainer(serverPlayer);
4243
container.checkReachable = this.checkReachable;
43-
container.setTitle(PaperAdventure.asVanilla(this.title));
44+
container.setTitle(this.title != null ? PaperAdventure.asVanilla(this.title) : this.defaultTitle);
4445
return (V) container.getBukkitView();
4546
}
4647

paper-server/src/main/java/org/bukkit/craftbukkit/inventory/view/builder/CraftAbstractLocationInventoryViewBuilder.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ public CraftAbstractLocationInventoryViewBuilder(final MenuType<?> handle) {
2222
}
2323

2424
@Override
25-
public LocationInventoryViewBuilder<V> title(final Component title) {
25+
public LocationInventoryViewBuilder<V> title(final @Nullable Component title) {
2626
return (LocationInventoryViewBuilder<V>) super.title(title);
2727
}
2828

0 commit comments

Comments
 (0)