mirror of
https://github.com/PaperMC/Paper.git
synced 2025-01-14 21:53:57 +01:00
MenuType API addition InventoryView Builders (#11816)
This commit is contained in:
parent
775002a357
commit
c94922514a
27 changed files with 759 additions and 95 deletions
build-data
paper-api/src/main/java/org/bukkit
paper-server
patches/sources/net/minecraft/world/inventory
AbstractContainerMenu.java.patchChestMenu.java.patchMerchantMenu.java.patchShulkerBoxMenu.java.patch
src/main/java/org/bukkit/craftbukkit
CraftServer.java
entity
event
inventory
CraftContainer.javaCraftMenuType.java
util
view/builder
CraftAbstractInventoryViewBuilder.javaCraftAbstractLocationInventoryViewBuilder.javaCraftAccessLocationInventoryViewBuilder.javaCraftBlockEntityInventoryViewBuilder.javaCraftDoubleChestInventoryViewBuilder.javaCraftMerchantInventoryViewBuilder.javaCraftStandardInventoryViewBuilder.javapackage-info.java
|
@ -725,6 +725,7 @@ public-f net.minecraft.world.item.trading.MerchantOffer rewardExp
|
|||
public-f net.minecraft.world.item.trading.MerchantOffer xp
|
||||
public-f net.minecraft.world.level.LevelSettings hardcore
|
||||
public-f net.minecraft.world.level.LevelSettings levelName
|
||||
public-f net.minecraft.world.level.block.ChestBlock MENU_PROVIDER_COMBINER
|
||||
public-f net.minecraft.world.level.block.entity.BannerBlockEntity baseColor
|
||||
public-f net.minecraft.world.level.block.entity.trialspawner.TrialSpawner normalConfig
|
||||
public-f net.minecraft.world.level.block.entity.trialspawner.TrialSpawner ominousConfig
|
||||
|
|
|
@ -40,6 +40,7 @@ import org.bukkit.inventory.InventoryHolder;
|
|||
import org.bukkit.inventory.ItemCraftResult;
|
||||
import org.bukkit.inventory.ItemFactory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.MenuType;
|
||||
import org.bukkit.inventory.Merchant;
|
||||
import org.bukkit.inventory.Recipe;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
@ -1925,7 +1926,10 @@ public final class Bukkit {
|
|||
* @param title the title of the corresponding merchant inventory, displayed
|
||||
* when the merchant inventory is viewed
|
||||
* @return a new merchant
|
||||
* @deprecated The title parameter is no-longer needed when used with
|
||||
* {@link MenuType#MERCHANT} and {@link MenuType.Typed#builder()}.
|
||||
*/
|
||||
@Deprecated(since = "1.21.4")
|
||||
public static @NotNull Merchant createMerchant(net.kyori.adventure.text.@Nullable Component title) {
|
||||
return server.createMerchant(title);
|
||||
}
|
||||
|
@ -1936,7 +1940,8 @@ public final class Bukkit {
|
|||
* @param title the title of the corresponding merchant inventory, displayed
|
||||
* when the merchant inventory is viewed
|
||||
* @return a new merchant
|
||||
* @deprecated in favour of {@link #createMerchant(net.kyori.adventure.text.Component)}
|
||||
* @deprecated in favour of {@link #createMerchant(net.kyori.adventure.text.Component)}. The title parameter is
|
||||
* no-longer needed when used with {@link MenuType#MERCHANT} and {@link MenuType.Typed#builder()}
|
||||
*/
|
||||
@NotNull
|
||||
@Deprecated // Paper
|
||||
|
@ -1944,6 +1949,16 @@ public final class Bukkit {
|
|||
return server.createMerchant(title);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty merchant.
|
||||
*
|
||||
* @return a new merchant
|
||||
*/
|
||||
@NotNull
|
||||
public static Merchant createMerchant() {
|
||||
return server.createMerchant();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the amount of consecutive neighbor updates before skipping
|
||||
* additional ones.
|
||||
|
|
|
@ -43,6 +43,7 @@ import org.bukkit.inventory.InventoryHolder;
|
|||
import org.bukkit.inventory.ItemCraftResult;
|
||||
import org.bukkit.inventory.ItemFactory;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.MenuType;
|
||||
import org.bukkit.inventory.Merchant;
|
||||
import org.bukkit.inventory.Recipe;
|
||||
import org.bukkit.inventory.meta.ItemMeta;
|
||||
|
@ -1565,11 +1566,11 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
|
|||
* <br>
|
||||
* {@link InventoryType#WORKBENCH} will not process crafting recipes if
|
||||
* created with this method. Use
|
||||
* {@link Player#openWorkbench(Location, boolean)} instead.
|
||||
* {@link MenuType#CRAFTING} instead.
|
||||
* <br>
|
||||
* {@link InventoryType#ENCHANTING} will not process {@link ItemStack}s
|
||||
* for possible enchanting results. Use
|
||||
* {@link Player#openEnchanting(Location, boolean)} instead.
|
||||
* {@link MenuType#ENCHANTMENT} instead.
|
||||
*
|
||||
* @param owner the holder of the inventory, or null to indicate no holder
|
||||
* @param type the type of inventory to create
|
||||
|
@ -1592,11 +1593,11 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
|
|||
* <br>
|
||||
* {@link InventoryType#WORKBENCH} will not process crafting recipes if
|
||||
* created with this method. Use
|
||||
* {@link Player#openWorkbench(Location, boolean)} instead.
|
||||
* {@link MenuType#CRAFTING} instead.
|
||||
* <br>
|
||||
* {@link InventoryType#ENCHANTING} will not process {@link ItemStack}s
|
||||
* for possible enchanting results. Use
|
||||
* {@link Player#openEnchanting(Location, boolean)} instead.
|
||||
* {@link MenuType#ENCHANTMENT} instead.
|
||||
*
|
||||
* @param owner The holder of the inventory; can be null if there's no holder.
|
||||
* @param type The type of inventory to create.
|
||||
|
@ -1620,11 +1621,11 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
|
|||
* <br>
|
||||
* {@link InventoryType#WORKBENCH} will not process crafting recipes if
|
||||
* created with this method. Use
|
||||
* {@link Player#openWorkbench(Location, boolean)} instead.
|
||||
* {@link MenuType#CRAFTING} instead.
|
||||
* <br>
|
||||
* {@link InventoryType#ENCHANTING} will not process {@link ItemStack}s
|
||||
* for possible enchanting results. Use
|
||||
* {@link Player#openEnchanting(Location, boolean)} instead.
|
||||
* {@link MenuType#ENCHANTMENT} instead.
|
||||
*
|
||||
* @param owner The holder of the inventory; can be null if there's no holder.
|
||||
* @param type The type of inventory to create.
|
||||
|
@ -1691,7 +1692,10 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
|
|||
* @param title the title of the corresponding merchant inventory, displayed
|
||||
* when the merchant inventory is viewed
|
||||
* @return a new merchant
|
||||
* @deprecated The title parameter is no-longer needed when used with
|
||||
* {@link MenuType#MERCHANT} and {@link MenuType.Typed#builder()}.
|
||||
*/
|
||||
@Deprecated(since = "1.21.4")
|
||||
@NotNull Merchant createMerchant(net.kyori.adventure.text.@Nullable Component title);
|
||||
// Paper start
|
||||
/**
|
||||
|
@ -1700,7 +1704,8 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
|
|||
* @param title the title of the corresponding merchant inventory, displayed
|
||||
* when the merchant inventory is viewed
|
||||
* @return a new merchant
|
||||
* @deprecated in favour of {@link #createMerchant(net.kyori.adventure.text.Component)}
|
||||
* @deprecated in favour of {@link #createMerchant(net.kyori.adventure.text.Component)}, The title parameter is
|
||||
* no-longer needed when used with {@link MenuType#MERCHANT} and {@link MenuType.Typed#builder()}.
|
||||
*/
|
||||
@NotNull
|
||||
@Deprecated // Paper
|
||||
|
@ -1715,6 +1720,14 @@ public interface Server extends PluginMessageRecipient, net.kyori.adventure.audi
|
|||
*/
|
||||
int getMaxChainedNeighborUpdates();
|
||||
|
||||
/**
|
||||
* Creates an empty merchant.
|
||||
*
|
||||
* @return a new merchant
|
||||
*/
|
||||
@NotNull
|
||||
Merchant createMerchant();
|
||||
|
||||
/**
|
||||
* Gets user-specified limit for number of monsters that can spawn in a
|
||||
* chunk.
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.bukkit.inventory.InventoryHolder;
|
|||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.inventory.MainHand;
|
||||
import org.bukkit.inventory.MenuType;
|
||||
import org.bukkit.inventory.Merchant;
|
||||
import org.bukkit.inventory.PlayerInventory;
|
||||
import org.bukkit.inventory.meta.FireworkMeta;
|
||||
|
@ -126,7 +127,10 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
|
|||
* no inventory will be opened and null will be returned.
|
||||
* @return The newly opened inventory view, or null if it could not be
|
||||
* opened.
|
||||
* @deprecated This method should be replaced by {@link MenuType#CRAFTING}
|
||||
* see {@link MenuType.Typed#builder()} and its options for more information.
|
||||
*/
|
||||
@Deprecated(since = "1.21.4")
|
||||
@Nullable
|
||||
public InventoryView openWorkbench(@Nullable Location location, boolean force);
|
||||
|
||||
|
@ -140,7 +144,10 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
|
|||
* location, no inventory will be opened and null will be returned.
|
||||
* @return The newly opened inventory view, or null if it could not be
|
||||
* opened.
|
||||
* @deprecated This method should be replaced by {@link MenuType#ENCHANTMENT}
|
||||
* see {@link MenuType.Typed#builder()} and its options for more information.
|
||||
*/
|
||||
@Deprecated(since = "1.21.4")
|
||||
@Nullable
|
||||
public InventoryView openEnchanting(@Nullable Location location, boolean force);
|
||||
|
||||
|
@ -166,8 +173,10 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
|
|||
* @param trader The merchant to trade with. Cannot be null.
|
||||
* @param force whether to force the trade even if another player is trading
|
||||
* @return The newly opened inventory view, or null if it could not be
|
||||
* opened.
|
||||
* @deprecated This method can be replaced by using {@link MenuType#MERCHANT}
|
||||
* in conjunction with {@link #openInventory(InventoryView)}.
|
||||
*/
|
||||
@Deprecated(since = "1.21.4")
|
||||
@Nullable
|
||||
public InventoryView openMerchant(@NotNull Villager trader, boolean force);
|
||||
|
||||
|
@ -180,8 +189,10 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
|
|||
* @param merchant The merchant to trade with. Cannot be null.
|
||||
* @param force whether to force the trade even if another player is trading
|
||||
* @return The newly opened inventory view, or null if it could not be
|
||||
* opened.
|
||||
* @deprecated This method can be replaced by using {@link MenuType#MERCHANT}
|
||||
* in conjunction with {@link #openInventory(InventoryView)}.
|
||||
*/
|
||||
@Deprecated(since = "1.21.4")
|
||||
@Nullable
|
||||
public InventoryView openMerchant(@NotNull Merchant merchant, boolean force);
|
||||
|
||||
|
@ -196,7 +207,10 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
|
|||
* no inventory will be opened and null will be returned.
|
||||
* @return The newly opened inventory view, or null if it could not be
|
||||
* opened.
|
||||
* @deprecated This method should be replaced by {@link MenuType#ANVIL}
|
||||
* see {@link MenuType.Typed#builder()} and its options for more information.
|
||||
*/
|
||||
@Deprecated(since = "1.21.4")
|
||||
@Nullable
|
||||
public InventoryView openAnvil(@Nullable Location location, boolean force);
|
||||
|
||||
|
@ -210,7 +224,10 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
|
|||
* no inventory will be opened and null will be returned.
|
||||
* @return The newly opened inventory view, or null if it could not be
|
||||
* opened.
|
||||
* @deprecated This method should be replaced by {@link MenuType#CARTOGRAPHY_TABLE}
|
||||
* see {@link MenuType.Typed#builder()} and its options for more information.
|
||||
*/
|
||||
@Deprecated(since = "1.21.4")
|
||||
@Nullable
|
||||
public InventoryView openCartographyTable(@Nullable Location location, boolean force);
|
||||
|
||||
|
@ -224,7 +241,10 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
|
|||
* no inventory will be opened and null will be returned.
|
||||
* @return The newly opened inventory view, or null if it could not be
|
||||
* opened.
|
||||
* @deprecated This method should be replaced by {@link MenuType#GRINDSTONE}
|
||||
* see {@link MenuType.Typed#builder()} and its options for more information.
|
||||
*/
|
||||
@Deprecated(since = "1.21.4")
|
||||
@Nullable
|
||||
public InventoryView openGrindstone(@Nullable Location location, boolean force);
|
||||
|
||||
|
@ -238,7 +258,10 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
|
|||
* no inventory will be opened and null will be returned.
|
||||
* @return The newly opened inventory view, or null if it could not be
|
||||
* opened.
|
||||
* @deprecated This method should be replaced by {@link MenuType#LOOM}
|
||||
* see {@link MenuType.Typed#builder()} and its options for more information.
|
||||
*/
|
||||
@Deprecated(since = "1.21.4")
|
||||
@Nullable
|
||||
public InventoryView openLoom(@Nullable Location location, boolean force);
|
||||
|
||||
|
@ -252,7 +275,10 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
|
|||
* no inventory will be opened and null will be returned.
|
||||
* @return The newly opened inventory view, or null if it could not be
|
||||
* opened.
|
||||
* @deprecated This method should be replaced by {@link MenuType#SMITHING}
|
||||
* see {@link MenuType.Typed#builder()} and its options for more information.
|
||||
*/
|
||||
@Deprecated(since = "1.21.4")
|
||||
@Nullable
|
||||
public InventoryView openSmithingTable(@Nullable Location location, boolean force);
|
||||
|
||||
|
@ -266,7 +292,10 @@ public interface HumanEntity extends LivingEntity, AnimalTamer, InventoryHolder
|
|||
* no inventory will be opened and null will be returned.
|
||||
* @return The newly opened inventory view, or null if it could not be
|
||||
* opened.
|
||||
* @deprecated This method should be replaced by {@link MenuType#STONECUTTER}
|
||||
* see {@link MenuType.Typed#builder()} and its options for more information.
|
||||
*/
|
||||
@Deprecated(since = "1.21.4")
|
||||
@Nullable
|
||||
public InventoryView openStonecutter(@Nullable Location location, boolean force);
|
||||
// Paper end
|
||||
|
|
|
@ -14,6 +14,9 @@ import org.bukkit.inventory.view.LecternView;
|
|||
import org.bukkit.inventory.view.LoomView;
|
||||
import org.bukkit.inventory.view.MerchantView;
|
||||
import org.bukkit.inventory.view.StonecutterView;
|
||||
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;
|
||||
|
||||
|
@ -27,104 +30,104 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe
|
|||
/**
|
||||
* A MenuType which represents a chest with 1 row.
|
||||
*/
|
||||
MenuType.Typed<InventoryView> GENERIC_9X1 = get("generic_9x1");
|
||||
MenuType.Typed<InventoryView, InventoryViewBuilder<InventoryView>> GENERIC_9X1 = get("generic_9x1");
|
||||
/**
|
||||
* A MenuType which represents a chest with 2 rows.
|
||||
*/
|
||||
MenuType.Typed<InventoryView> GENERIC_9X2 = get("generic_9x2");
|
||||
MenuType.Typed<InventoryView, InventoryViewBuilder<InventoryView>> GENERIC_9X2 = get("generic_9x2");
|
||||
/**
|
||||
* A MenuType which represents a chest with 3 rows.
|
||||
*/
|
||||
MenuType.Typed<InventoryView> GENERIC_9X3 = get("generic_9x3");
|
||||
MenuType.Typed<InventoryView, LocationInventoryViewBuilder<InventoryView>> GENERIC_9X3 = get("generic_9x3");
|
||||
/**
|
||||
* A MenuType which represents a chest with 4 rows.
|
||||
*/
|
||||
MenuType.Typed<InventoryView> GENERIC_9X4 = get("generic_9x4");
|
||||
MenuType.Typed<InventoryView, InventoryViewBuilder<InventoryView>> GENERIC_9X4 = get("generic_9x4");
|
||||
/**
|
||||
* A MenuType which represents a chest with 5 rows.
|
||||
*/
|
||||
MenuType.Typed<InventoryView> GENERIC_9X5 = get("generic_9x5");
|
||||
MenuType.Typed<InventoryView, InventoryViewBuilder<InventoryView>> GENERIC_9X5 = get("generic_9x5");
|
||||
/**
|
||||
* A MenuType which represents a chest with 6 rows.
|
||||
*/
|
||||
MenuType.Typed<InventoryView> GENERIC_9X6 = get("generic_9x6");
|
||||
MenuType.Typed<InventoryView, LocationInventoryViewBuilder<InventoryView>> GENERIC_9X6 = get("generic_9x6");
|
||||
/**
|
||||
* A MenuType which represents a dispenser/dropper like menu with 3 columns
|
||||
* and 3 rows.
|
||||
*/
|
||||
MenuType.Typed<InventoryView> GENERIC_3X3 = get("generic_3x3");
|
||||
MenuType.Typed<InventoryView, LocationInventoryViewBuilder<InventoryView>> GENERIC_3X3 = get("generic_3x3");
|
||||
/**
|
||||
* A MenuType which represents a crafter
|
||||
*/
|
||||
MenuType.Typed<CrafterView> CRAFTER_3X3 = get("crafter_3x3");
|
||||
MenuType.Typed<CrafterView, LocationInventoryViewBuilder<CrafterView>> CRAFTER_3X3 = get("crafter_3x3");
|
||||
/**
|
||||
* A MenuType which represents an anvil.
|
||||
*/
|
||||
MenuType.Typed<AnvilView> ANVIL = get("anvil");
|
||||
MenuType.Typed<AnvilView, LocationInventoryViewBuilder<AnvilView>> ANVIL = get("anvil");
|
||||
/**
|
||||
* A MenuType which represents a beacon.
|
||||
*/
|
||||
MenuType.Typed<BeaconView> BEACON = get("beacon");
|
||||
MenuType.Typed<BeaconView, LocationInventoryViewBuilder<BeaconView>> BEACON = get("beacon");
|
||||
/**
|
||||
* A MenuType which represents a blast furnace.
|
||||
*/
|
||||
MenuType.Typed<FurnaceView> BLAST_FURNACE = get("blast_furnace");
|
||||
MenuType.Typed<FurnaceView, LocationInventoryViewBuilder<FurnaceView>> BLAST_FURNACE = get("blast_furnace");
|
||||
/**
|
||||
* A MenuType which represents a brewing stand.
|
||||
*/
|
||||
MenuType.Typed<BrewingStandView> BREWING_STAND = get("brewing_stand");
|
||||
MenuType.Typed<BrewingStandView, LocationInventoryViewBuilder<BrewingStandView>> BREWING_STAND = get("brewing_stand");
|
||||
/**
|
||||
* A MenuType which represents a crafting table.
|
||||
*/
|
||||
MenuType.Typed<InventoryView> CRAFTING = get("crafting");
|
||||
MenuType.Typed<InventoryView, LocationInventoryViewBuilder<InventoryView>> CRAFTING = get("crafting");
|
||||
/**
|
||||
* A MenuType which represents an enchantment table.
|
||||
*/
|
||||
MenuType.Typed<EnchantmentView> ENCHANTMENT = get("enchantment");
|
||||
MenuType.Typed<EnchantmentView, LocationInventoryViewBuilder<EnchantmentView>> ENCHANTMENT = get("enchantment");
|
||||
/**
|
||||
* A MenuType which represents a furnace.
|
||||
*/
|
||||
MenuType.Typed<FurnaceView> FURNACE = get("furnace");
|
||||
MenuType.Typed<FurnaceView, LocationInventoryViewBuilder<FurnaceView>> FURNACE = get("furnace");
|
||||
/**
|
||||
* A MenuType which represents a grindstone.
|
||||
*/
|
||||
MenuType.Typed<InventoryView> GRINDSTONE = get("grindstone");
|
||||
MenuType.Typed<InventoryView, LocationInventoryViewBuilder<InventoryView>> GRINDSTONE = get("grindstone");
|
||||
/**
|
||||
* A MenuType which represents a hopper.
|
||||
*/
|
||||
MenuType.Typed<InventoryView> HOPPER = get("hopper");
|
||||
MenuType.Typed<InventoryView, LocationInventoryViewBuilder<InventoryView>> HOPPER = get("hopper");
|
||||
/**
|
||||
* A MenuType which represents a lectern, a book like view.
|
||||
*/
|
||||
MenuType.Typed<LecternView> LECTERN = get("lectern");
|
||||
MenuType.Typed<LecternView, LocationInventoryViewBuilder<LecternView>> LECTERN = get("lectern");
|
||||
/**
|
||||
* A MenuType which represents a loom.
|
||||
*/
|
||||
MenuType.Typed<LoomView> LOOM = get("loom");
|
||||
MenuType.Typed<LoomView, LocationInventoryViewBuilder<LoomView>> LOOM = get("loom");
|
||||
/**
|
||||
* A MenuType which represents a merchant.
|
||||
*/
|
||||
MenuType.Typed<MerchantView> MERCHANT = get("merchant");
|
||||
MenuType.Typed<MerchantView, MerchantInventoryViewBuilder<MerchantView>> MERCHANT = get("merchant");
|
||||
/**
|
||||
* A MenuType which represents a shulker box.
|
||||
*/
|
||||
MenuType.Typed<InventoryView> SHULKER_BOX = get("shulker_box");
|
||||
MenuType.Typed<InventoryView, LocationInventoryViewBuilder<InventoryView>> SHULKER_BOX = get("shulker_box");
|
||||
/**
|
||||
* A MenuType which represents a stonecutter.
|
||||
*/
|
||||
MenuType.Typed<InventoryView> SMITHING = get("smithing");
|
||||
MenuType.Typed<InventoryView, LocationInventoryViewBuilder<InventoryView>> SMITHING = get("smithing");
|
||||
/**
|
||||
* A MenuType which represents a smoker.
|
||||
*/
|
||||
MenuType.Typed<FurnaceView> SMOKER = get("smoker");
|
||||
MenuType.Typed<FurnaceView, LocationInventoryViewBuilder<FurnaceView>> SMOKER = get("smoker");
|
||||
/**
|
||||
* A MenuType which represents a cartography table.
|
||||
*/
|
||||
MenuType.Typed<InventoryView> CARTOGRAPHY_TABLE = get("cartography_table");
|
||||
MenuType.Typed<InventoryView, LocationInventoryViewBuilder<InventoryView>> CARTOGRAPHY_TABLE = get("cartography_table");
|
||||
/**
|
||||
* A MenuType which represents a stonecutter.
|
||||
*/
|
||||
MenuType.Typed<StonecutterView> STONECUTTER = get("stonecutter");
|
||||
MenuType.Typed<StonecutterView, LocationInventoryViewBuilder<StonecutterView>> STONECUTTER = get("stonecutter");
|
||||
|
||||
/**
|
||||
* Typed represents a subtype of {@link MenuType}s that have a known
|
||||
|
@ -133,7 +136,7 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe
|
|||
* @param <V> the generic type of {@link InventoryView} that represents the
|
||||
* view type.
|
||||
*/
|
||||
interface Typed<V extends InventoryView> extends MenuType {
|
||||
interface Typed<V extends InventoryView, B extends InventoryViewBuilder<V>> extends MenuType {
|
||||
|
||||
/**
|
||||
* Creates a view of the specified menu type.
|
||||
|
@ -166,6 +169,9 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe
|
|||
@NotNull
|
||||
V create(@NotNull HumanEntity player, @NotNull net.kyori.adventure.text.Component title);
|
||||
// Paper end - adventure
|
||||
|
||||
@NotNull
|
||||
B builder();
|
||||
}
|
||||
|
||||
// Paper start - adventure
|
||||
|
@ -191,7 +197,7 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe
|
|||
* @return the typed MenuType.
|
||||
*/
|
||||
@NotNull
|
||||
MenuType.Typed<InventoryView> typed();
|
||||
MenuType.Typed<InventoryView, InventoryViewBuilder<InventoryView>> typed();
|
||||
|
||||
/**
|
||||
* Yields this MenuType as a typed version of itself with a specific
|
||||
|
@ -201,12 +207,14 @@ public interface MenuType extends Keyed, io.papermc.paper.world.flag.FeatureDepe
|
|||
* {@link InventoryView} with.
|
||||
* @param <V> the generic type of the InventoryView to get this MenuType
|
||||
* with
|
||||
* @param <B> the generic type of the InventoryViewBuilder to get this
|
||||
* MenuType with
|
||||
* @return the typed MenuType
|
||||
* @throws IllegalArgumentException if the provided viewClass cannot be
|
||||
* typed to this MenuType
|
||||
*/
|
||||
@NotNull
|
||||
<V extends InventoryView> MenuType.Typed<V> typed(@NotNull final Class<V> viewClass) throws IllegalArgumentException;
|
||||
<V extends InventoryView, B extends InventoryViewBuilder<V>> MenuType.Typed<V, B> typed(@NotNull final Class<V> viewClass) throws IllegalArgumentException;
|
||||
|
||||
/**
|
||||
* Gets the {@link InventoryView} class of this MenuType.
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
package org.bukkit.inventory.view.builder;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
|
||||
/**
|
||||
* Generic Builder for InventoryView's with no special attributes or parameters
|
||||
*
|
||||
* @param <V> the type of InventoryView created from this builder
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public interface InventoryViewBuilder<V extends InventoryView> {
|
||||
|
||||
/**
|
||||
* Makes a copy of this builder
|
||||
*
|
||||
* @return a copy of this builder
|
||||
*/
|
||||
InventoryViewBuilder<V> copy();
|
||||
|
||||
/**
|
||||
* Sets the title of the builder
|
||||
*
|
||||
* @param title the title
|
||||
* @return this builder
|
||||
*/
|
||||
InventoryViewBuilder<V> title(final Component title);
|
||||
|
||||
/**
|
||||
* Builds this builder into a InventoryView
|
||||
*
|
||||
* @param player the player to assign to the view
|
||||
* @return the created InventoryView
|
||||
*/
|
||||
V build(final HumanEntity player);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package org.bukkit.inventory.view.builder;
|
||||
|
||||
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;
|
||||
|
||||
/**
|
||||
* An InventoryViewBuilder that can be bound by location within the world
|
||||
*
|
||||
* @param <V> the type of InventoryView created from this builder
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public interface LocationInventoryViewBuilder<V extends InventoryView> extends InventoryViewBuilder<V> {
|
||||
|
||||
@Override
|
||||
LocationInventoryViewBuilder<V> copy();
|
||||
|
||||
@Override
|
||||
LocationInventoryViewBuilder<V> title(final @NotNull Component title);
|
||||
|
||||
/**
|
||||
* Determines whether or not the server should check if the player can reach
|
||||
* the location.
|
||||
* <p>
|
||||
* Not providing a location but setting checkReachable to true will
|
||||
* automatically close the view when opened.
|
||||
* <p>
|
||||
* If checkReachable is set to false and a location is set on the builder if
|
||||
* the target block exists and this builder is the correct menu for that
|
||||
* block, e.g. MenuType.GENERIC_9X3 builder and target block set to chest,
|
||||
* if that block is destroyed the view would persist.
|
||||
*
|
||||
* @param checkReachable whether or not to check if the view is "reachable"
|
||||
* @return this builder
|
||||
*/
|
||||
LocationInventoryViewBuilder<V> checkReachable(final boolean checkReachable);
|
||||
|
||||
/**
|
||||
* Binds a location to this builder.
|
||||
* <p>
|
||||
* By binding a location in an unloaded chunk to this builder it is likely
|
||||
* that the given chunk the location is will load. That means that when,
|
||||
* building this view it may come with the costs associated with chunk
|
||||
* loading.
|
||||
* <p>
|
||||
* Providing a location of a tile entity with a non matching menu comes with
|
||||
* extra costs associated with ensuring that the correct view is created.
|
||||
*
|
||||
* @param location the location to bind to this view
|
||||
* @return this builder
|
||||
*/
|
||||
LocationInventoryViewBuilder<V> location(final Location location);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package org.bukkit.inventory.view.builder;
|
||||
|
||||
import net.kyori.adventure.text.Component;
|
||||
import org.bukkit.Server;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.Merchant;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* An InventoryViewBuilder for creating merchant views
|
||||
*
|
||||
* @param <V> the type of InventoryView created by this builder
|
||||
*/
|
||||
@ApiStatus.Experimental
|
||||
public interface MerchantInventoryViewBuilder<V extends InventoryView> extends InventoryViewBuilder<V> {
|
||||
|
||||
@Override
|
||||
MerchantInventoryViewBuilder<V> copy();
|
||||
|
||||
@Override
|
||||
MerchantInventoryViewBuilder<V> title(final @NotNull Component title);
|
||||
|
||||
/**
|
||||
* Adds a merchant to this builder
|
||||
*
|
||||
* @param merchant the merchant
|
||||
* @return this builder
|
||||
*/
|
||||
MerchantInventoryViewBuilder<V> merchant(final Merchant merchant);
|
||||
|
||||
/**
|
||||
* Determines whether or not the server should check if the player can reach
|
||||
* the location.
|
||||
* <p>
|
||||
* Given checkReachable is provided and a virtual merchant is provided to
|
||||
* the builder from {@link Server#createMerchant(net.kyori.adventure.text.Component)} this method will
|
||||
* have no effect on the actual menu status.
|
||||
*
|
||||
* @param checkReachable whether or not to check if the view is "reachable"
|
||||
* @return this builder
|
||||
*/
|
||||
MerchantInventoryViewBuilder<V> checkReachable(final boolean checkReachable);
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
/**
|
||||
* A Package that contains builders for building InventoryViews.
|
||||
*/
|
||||
@NullMarked
|
||||
@ApiStatus.Experimental
|
||||
package org.bukkit.inventory.view.builder;
|
||||
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jspecify.annotations.NullMarked;
|
|
@ -9,7 +9,7 @@
|
|||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.Container;
|
||||
@@ -63,6 +_,31 @@
|
||||
@@ -63,6 +_,32 @@
|
||||
@Nullable
|
||||
private ContainerSynchronizer synchronizer;
|
||||
private boolean suppressRemoteUpdates;
|
||||
|
@ -37,6 +37,7 @@
|
|||
+ com.google.common.base.Preconditions.checkState(this.title == null, "Title already set");
|
||||
+ this.title = title;
|
||||
+ }
|
||||
+ public void startOpen() {}
|
||||
+ // CraftBukkit end
|
||||
|
||||
protected AbstractContainerMenu(@Nullable MenuType<?> menuType, int containerId) {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
--- a/net/minecraft/world/inventory/ChestMenu.java
|
||||
+++ b/net/minecraft/world/inventory/ChestMenu.java
|
||||
@@ -9,6 +_,29 @@
|
||||
@@ -9,6 +_,34 @@
|
||||
public class ChestMenu extends AbstractContainerMenu {
|
||||
private final Container container;
|
||||
private final int containerRows;
|
||||
|
@ -26,14 +26,21 @@
|
|||
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.CraftInventoryView(this.player.player.getBukkitEntity(), inventory, this);
|
||||
+ return this.bukkitEntity;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void startOpen() {
|
||||
+ this.container.startOpen(this.player.player);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
|
||||
private ChestMenu(MenuType<?> type, int containerId, Inventory playerInventory, int rows) {
|
||||
this(type, containerId, playerInventory, new SimpleContainer(9 * rows), rows);
|
||||
@@ -52,6 +_,9 @@
|
||||
@@ -51,7 +_,10 @@
|
||||
checkContainerSize(container, rows * 9);
|
||||
this.container = container;
|
||||
this.containerRows = rows;
|
||||
container.startOpen(playerInventory.player);
|
||||
- container.startOpen(playerInventory.player);
|
||||
+ // container.startOpen(playerInventory.player); // Paper - don't startOpen until menu actually opens
|
||||
+ // CraftBukkit start - Save player
|
||||
+ this.player = playerInventory;
|
||||
+ // CraftBukkit end
|
||||
|
|
|
@ -27,6 +27,14 @@
|
|||
this.addStandardInventorySlots(playerInventory, 108, 84);
|
||||
}
|
||||
|
||||
@@ -61,6 +_,7 @@
|
||||
|
||||
@Override
|
||||
public boolean stillValid(Player player) {
|
||||
+ if (!checkReachable) return true; // Paper - checkReachable
|
||||
return this.trader.stillValid(player);
|
||||
}
|
||||
|
||||
@@ -105,12 +_,12 @@
|
||||
ItemStack item = slot.getItem();
|
||||
itemStack = item.copy();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
--- a/net/minecraft/world/inventory/ShulkerBoxMenu.java
|
||||
+++ b/net/minecraft/world/inventory/ShulkerBoxMenu.java
|
||||
@@ -9,6 +_,20 @@
|
||||
@@ -9,6 +_,25 @@
|
||||
public class ShulkerBoxMenu extends AbstractContainerMenu {
|
||||
private static final int CONTAINER_SIZE = 27;
|
||||
private final Container container;
|
||||
|
@ -17,18 +17,25 @@
|
|||
+ this.bukkitEntity = new org.bukkit.craftbukkit.inventory.CraftInventoryView(this.player.player.getBukkitEntity(), new org.bukkit.craftbukkit.inventory.CraftInventory(this.container), this);
|
||||
+ return this.bukkitEntity;
|
||||
+ }
|
||||
+
|
||||
+ @Override
|
||||
+ public void startOpen() {
|
||||
+ container.startOpen(player.player);
|
||||
+ }
|
||||
+ // CraftBukkit end
|
||||
|
||||
public ShulkerBoxMenu(int containerId, Inventory playerInventory) {
|
||||
this(containerId, playerInventory, new SimpleContainer(27));
|
||||
@@ -18,6 +_,7 @@
|
||||
@@ -18,7 +_,8 @@
|
||||
super(MenuType.SHULKER_BOX, containerId);
|
||||
checkContainerSize(container, 27);
|
||||
this.container = container;
|
||||
- container.startOpen(playerInventory.player);
|
||||
+ this.player = playerInventory; // CraftBukkit - save player
|
||||
container.startOpen(playerInventory.player);
|
||||
+ // container.startOpen(playerInventory.player); // Paper - don't startOpen until menu actually opens
|
||||
int i = 3;
|
||||
int i1 = 9;
|
||||
|
||||
@@ -33,6 +_,7 @@
|
||||
|
||||
@Override
|
||||
|
|
|
@ -258,6 +258,7 @@ import org.bukkit.scoreboard.Criteria;
|
|||
import org.bukkit.structure.StructureManager;
|
||||
import org.bukkit.util.StringUtil;
|
||||
import org.bukkit.util.permissions.DefaultPermissions;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.yaml.snakeyaml.LoaderOptions;
|
||||
import org.yaml.snakeyaml.Yaml;
|
||||
import org.yaml.snakeyaml.constructor.SafeConstructor;
|
||||
|
@ -2485,6 +2486,11 @@ public final class CraftServer implements Server {
|
|||
return new CraftMerchantCustom(title == null ? InventoryType.MERCHANT.getDefaultTitle() : title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Merchant createMerchant() {
|
||||
return new CraftMerchantCustom(net.kyori.adventure.text.Component.empty());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxChainedNeighborUpdates() {
|
||||
return this.getServer().getMaxChainedNeighborUpdates();
|
||||
|
|
|
@ -25,6 +25,7 @@ import net.minecraft.world.entity.player.Player;
|
|||
import net.minecraft.world.entity.projectile.FireworkRocketEntity;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.inventory.MerchantMenu;
|
||||
import net.minecraft.world.item.ItemCooldowns;
|
||||
import net.minecraft.world.item.crafting.RecipeHolder;
|
||||
import net.minecraft.world.item.crafting.RecipeManager;
|
||||
|
@ -50,6 +51,8 @@ import org.bukkit.craftbukkit.inventory.CraftInventoryView;
|
|||
import org.bukkit.craftbukkit.inventory.CraftItemStack;
|
||||
import org.bukkit.craftbukkit.inventory.CraftMerchantCustom;
|
||||
import org.bukkit.craftbukkit.inventory.CraftRecipe;
|
||||
import org.bukkit.craftbukkit.inventory.util.CraftMenus;
|
||||
import org.bukkit.craftbukkit.util.CraftChatMessage;
|
||||
import org.bukkit.craftbukkit.util.CraftLocation;
|
||||
import org.bukkit.entity.Firework;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
|
@ -467,6 +470,11 @@ public class CraftHumanEntity extends CraftLivingEntity implements HumanEntity {
|
|||
|
||||
// Now open the window
|
||||
MenuType<?> windowType = CraftContainer.getNotchInventoryType(inventory.getTopInventory());
|
||||
// we can open these now, delegate for now
|
||||
if (windowType == MenuType.MERCHANT) {
|
||||
CraftMenus.openMerchantMenu(player, (MerchantMenu) container);
|
||||
return;
|
||||
}
|
||||
|
||||
//String title = inventory.getTitle(); // Paper - comment
|
||||
net.kyori.adventure.text.Component adventure$title = inventory.title(); // Paper
|
||||
|
|
|
@ -1430,6 +1430,7 @@ public class CraftEventFactory {
|
|||
}
|
||||
public static com.mojang.datafixers.util.Pair<net.kyori.adventure.text.@org.jetbrains.annotations.Nullable Component, @org.jetbrains.annotations.Nullable AbstractContainerMenu> callInventoryOpenEventWithTitle(ServerPlayer player, AbstractContainerMenu container, boolean cancelled) {
|
||||
// Paper end - Add titleOverride to InventoryOpenEvent
|
||||
container.startOpen(); // delegate start open logic to before InventoryOpenEvent is fired
|
||||
if (player.containerMenu != player.inventoryMenu) { // fire INVENTORY_CLOSE if one already open
|
||||
player.connection.handleContainerClose(new ServerboundContainerClosePacket(player.containerMenu.containerId), InventoryCloseEvent.Reason.OPEN_NEW); // Paper - Inventory close reason
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ public class CraftContainer extends AbstractContainerMenu {
|
|||
if (menu == null) {
|
||||
return net.minecraft.world.inventory.MenuType.GENERIC_9x3;
|
||||
} else {
|
||||
return ((CraftMenuType<?>) menu).getHandle();
|
||||
return ((CraftMenuType<?, ?>) menu).getHandle();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,12 +15,14 @@ import org.bukkit.craftbukkit.util.Handleable;
|
|||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.MenuType;
|
||||
import org.bukkit.inventory.view.builder.InventoryViewBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class CraftMenuType<V extends InventoryView> implements MenuType.Typed<V>, Handleable<net.minecraft.world.inventory.MenuType<?>>, io.papermc.paper.world.flag.PaperFeatureDependent { // Paper - make FeatureDependant
|
||||
public class CraftMenuType<V extends InventoryView, B extends InventoryViewBuilder<V>> implements MenuType.Typed<V, B>, Handleable<net.minecraft.world.inventory.MenuType<?>>, io.papermc.paper.world.flag.PaperFeatureDependent { // Paper - make FeatureDependant
|
||||
|
||||
private final NamespacedKey key;
|
||||
private final net.minecraft.world.inventory.MenuType<?> handle;
|
||||
private final Supplier<CraftMenus.MenuTypeData<V>> typeData;
|
||||
private final Supplier<CraftMenus.MenuTypeData<V, B>> typeData;
|
||||
|
||||
public CraftMenuType(NamespacedKey key, net.minecraft.world.inventory.MenuType<?> handle) {
|
||||
this.key = key;
|
||||
|
@ -36,33 +38,28 @@ public class CraftMenuType<V extends InventoryView> implements MenuType.Typed<V>
|
|||
@Override
|
||||
public V create(final HumanEntity player, final String title) {
|
||||
// Paper start - adventure
|
||||
return create(player, net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(title));
|
||||
return builder().title(net.kyori.adventure.text.serializer.legacy.LegacyComponentSerializer.legacySection().deserialize(title)).build(player);
|
||||
}
|
||||
@Override
|
||||
public V create(final HumanEntity player, final net.kyori.adventure.text.Component title) {
|
||||
// Paper end - adventure
|
||||
Preconditions.checkArgument(player != null, "The given player must not be null");
|
||||
Preconditions.checkArgument(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");
|
||||
final ServerPlayer serverPlayer = (ServerPlayer) craftHuman.getHandle();
|
||||
|
||||
final AbstractContainerMenu container = this.typeData.get().menuBuilder().build(serverPlayer, this.handle);
|
||||
container.setTitle(io.papermc.paper.adventure.PaperAdventure.asVanilla(title)); // Paper - adventure
|
||||
container.checkReachable = false;
|
||||
return (V) container.getBukkitView();
|
||||
return builder().title(title).build(player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Typed<InventoryView> typed() {
|
||||
public B builder() {
|
||||
return typeData.get().viewBuilder().get();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Typed<InventoryView, InventoryViewBuilder<InventoryView>> typed() {
|
||||
return this.typed(InventoryView.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <V extends InventoryView> Typed<V> typed(Class<V> clazz) {
|
||||
public <V extends InventoryView, B extends InventoryViewBuilder<V>> Typed<V, B> typed(Class<V> clazz) {
|
||||
if (clazz.isAssignableFrom(this.typeData.get().viewClass())) {
|
||||
return (Typed<V>) this;
|
||||
return (Typed<V, B>) this;
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Cannot type InventoryView " + this.key.toString() + " to InventoryView type " + clazz.getSimpleName());
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
package org.bukkit.craftbukkit.inventory.util;
|
||||
|
||||
import static org.bukkit.craftbukkit.inventory.util.CraftMenuBuilder.*;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.SimpleMenuProvider;
|
||||
import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.npc.Villager;
|
||||
import net.minecraft.world.inventory.AnvilMenu;
|
||||
import net.minecraft.world.inventory.CartographyTableMenu;
|
||||
import net.minecraft.world.inventory.CraftingMenu;
|
||||
import net.minecraft.world.inventory.EnchantmentMenu;
|
||||
import net.minecraft.world.inventory.GrindstoneMenu;
|
||||
import net.minecraft.world.inventory.MerchantMenu;
|
||||
import net.minecraft.world.inventory.SmithingMenu;
|
||||
import net.minecraft.world.inventory.StonecutterMenu;
|
||||
import net.minecraft.world.item.trading.Merchant;
|
||||
import net.minecraft.world.item.trading.MerchantOffers;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.entity.BeaconBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlastFurnaceBlockEntity;
|
||||
|
@ -20,8 +22,15 @@ import net.minecraft.world.level.block.entity.DispenserBlockEntity;
|
|||
import net.minecraft.world.level.block.entity.FurnaceBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.HopperBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.LecternBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.ShulkerBoxBlockEntity;
|
||||
import net.minecraft.world.level.block.entity.SmokerBlockEntity;
|
||||
import org.bukkit.craftbukkit.inventory.CraftMenuType;
|
||||
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.CraftMerchantInventoryViewBuilder;
|
||||
import org.bukkit.craftbukkit.inventory.view.builder.CraftStandardInventoryViewBuilder;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.MenuType;
|
||||
import org.bukkit.inventory.view.AnvilView;
|
||||
|
@ -34,83 +43,120 @@ import org.bukkit.inventory.view.LecternView;
|
|||
import org.bukkit.inventory.view.LoomView;
|
||||
import org.bukkit.inventory.view.MerchantView;
|
||||
import org.bukkit.inventory.view.StonecutterView;
|
||||
import org.bukkit.inventory.view.builder.InventoryViewBuilder;
|
||||
import org.jspecify.annotations.NullMarked;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@NullMarked
|
||||
public final class CraftMenus {
|
||||
|
||||
public record MenuTypeData<V extends InventoryView>(Class<V> viewClass, CraftMenuBuilder menuBuilder) {
|
||||
public record MenuTypeData<V extends InventoryView, B extends InventoryViewBuilder<V>>(Class<V> viewClass, Supplier<B> viewBuilder) {
|
||||
}
|
||||
|
||||
private static final CraftMenuBuilder STANDARD = (player, menuType) -> menuType.create(player.nextContainerCounter(), player.getInventory());
|
||||
// This is a temporary measure that will likely be removed with the rewrite of HumanEntity#open[] methods
|
||||
public static void openMerchantMenu(final ServerPlayer player, final MerchantMenu merchant) {
|
||||
final Merchant minecraftMerchant = ((CraftMerchant) merchant.getBukkitView().getMerchant()).getMerchant();
|
||||
int level = 1;
|
||||
if (minecraftMerchant instanceof final Villager villager) {
|
||||
level = villager.getVillagerData().getLevel();
|
||||
}
|
||||
|
||||
public static <V extends InventoryView> MenuTypeData<V> getMenuTypeData(CraftMenuType<?> menuType) {
|
||||
if (minecraftMerchant.getTradingPlayer() != null) { // merchant's can only have one trader
|
||||
minecraftMerchant.getTradingPlayer().closeContainer();
|
||||
}
|
||||
|
||||
minecraftMerchant.setTradingPlayer(player);
|
||||
|
||||
player.connection.send(new ClientboundOpenScreenPacket(merchant.containerId, net.minecraft.world.inventory.MenuType.MERCHANT, merchant.getTitle()));
|
||||
player.containerMenu = merchant;
|
||||
player.initMenu(merchant);
|
||||
// Copy IMerchant#openTradingScreen
|
||||
MerchantOffers merchantrecipelist = minecraftMerchant.getOffers();
|
||||
|
||||
if (!merchantrecipelist.isEmpty()) {
|
||||
player.sendMerchantOffers(merchant.containerId, merchantrecipelist, level, minecraftMerchant.getVillagerXp(), minecraftMerchant.showProgressBar(), minecraftMerchant.canRestock());
|
||||
}
|
||||
// End Copy IMerchant#openTradingScreen
|
||||
}
|
||||
|
||||
public static <V extends InventoryView, B extends InventoryViewBuilder<V>> MenuTypeData<V, B> getMenuTypeData(final CraftMenuType<?, ?> menuType) {
|
||||
final net.minecraft.world.inventory.MenuType<?> handle = menuType.getHandle();
|
||||
// this sucks horribly but it should work for now
|
||||
if (menuType == MenuType.GENERIC_9X6) {
|
||||
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)));
|
||||
}
|
||||
// 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
|
||||
if (menuType == MenuType.GENERIC_3X3) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(InventoryView.class, tileEntity(DispenserBlockEntity::new, Blocks.DISPENSER)));
|
||||
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.DISPENSER, DispenserBlockEntity::new)));
|
||||
}
|
||||
if (menuType == MenuType.CRAFTER_3X3) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(CrafterView.class, tileEntity(CrafterBlockEntity::new, Blocks.CRAFTER)));
|
||||
return asType(new MenuTypeData<>(CrafterView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.CRAFTER, CrafterBlockEntity::new)));
|
||||
}
|
||||
if (menuType == MenuType.ANVIL) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(AnvilView.class, worldAccess(AnvilMenu::new)));
|
||||
return asType(new MenuTypeData<>(AnvilView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, AnvilMenu::new)));
|
||||
}
|
||||
if (menuType == MenuType.BEACON) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(BeaconView.class, tileEntity(BeaconBlockEntity::new, Blocks.BEACON)));
|
||||
return asType(new MenuTypeData<>(BeaconView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.BEACON, BeaconBlockEntity::new)));
|
||||
}
|
||||
if (menuType == MenuType.BLAST_FURNACE) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(FurnaceView.class, tileEntity(BlastFurnaceBlockEntity::new, Blocks.BLAST_FURNACE)));
|
||||
return asType(new MenuTypeData<>(FurnaceView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.BLAST_FURNACE, BlastFurnaceBlockEntity::new)));
|
||||
}
|
||||
if (menuType == MenuType.BREWING_STAND) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(BrewingStandView.class, tileEntity(BrewingStandBlockEntity::new, Blocks.BREWING_STAND)));
|
||||
return asType(new MenuTypeData<>(BrewingStandView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.BREWING_STAND, BrewingStandBlockEntity::new)));
|
||||
}
|
||||
if (menuType == MenuType.CRAFTING) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(InventoryView.class, worldAccess(CraftingMenu::new)));
|
||||
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, CraftingMenu::new)));
|
||||
}
|
||||
if (menuType == MenuType.ENCHANTMENT) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(EnchantmentView.class, (player, type) -> {
|
||||
return new SimpleMenuProvider((syncId, inventory, human) -> {
|
||||
return worldAccess(EnchantmentMenu::new).build(player, type);
|
||||
}, Component.empty()).createMenu(player.nextContainerCounter(), player.getInventory(), player);
|
||||
}));
|
||||
return asType(new MenuTypeData<>(EnchantmentView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, EnchantmentMenu::new)));
|
||||
}
|
||||
if (menuType == MenuType.FURNACE) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(FurnaceView.class, tileEntity(FurnaceBlockEntity::new, Blocks.FURNACE)));
|
||||
return asType(new MenuTypeData<>(FurnaceView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.FURNACE, FurnaceBlockEntity::new)));
|
||||
}
|
||||
if (menuType == MenuType.GRINDSTONE) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(InventoryView.class, worldAccess(GrindstoneMenu::new)));
|
||||
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, GrindstoneMenu::new)));
|
||||
}
|
||||
// We really don't need to be creating a tile entity for hopper but currently InventoryType doesn't have capacity
|
||||
// to understand otherwise
|
||||
if (menuType == MenuType.HOPPER) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(InventoryView.class, tileEntity(HopperBlockEntity::new, Blocks.HOPPER)));
|
||||
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.HOPPER, HopperBlockEntity::new)));
|
||||
}
|
||||
// We also don't need to create a tile entity for lectern, but again InventoryType isn't smart enough to know any better
|
||||
if (menuType == MenuType.LECTERN) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(LecternView.class, tileEntity(LecternBlockEntity::new, Blocks.LECTERN)));
|
||||
return asType(new MenuTypeData<>(LecternView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.LECTERN, LecternBlockEntity::new)));
|
||||
}
|
||||
if (menuType == MenuType.LOOM) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(LoomView.class, CraftMenus.STANDARD));
|
||||
return asType(new MenuTypeData<>(LoomView.class, () -> new CraftStandardInventoryViewBuilder<>(handle)));
|
||||
}
|
||||
if (menuType == MenuType.MERCHANT) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(MerchantView.class, CraftMenus.STANDARD));
|
||||
return asType(new MenuTypeData<>(MerchantView.class, () -> new CraftMerchantInventoryViewBuilder<>(handle)));
|
||||
}
|
||||
if (menuType == MenuType.SHULKER_BOX) {
|
||||
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.SHULKER_BOX, ShulkerBoxBlockEntity::new)));
|
||||
}
|
||||
if (menuType == MenuType.SMITHING) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(InventoryView.class, worldAccess(SmithingMenu::new)));
|
||||
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, SmithingMenu::new)));
|
||||
}
|
||||
if (menuType == MenuType.SMOKER) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(FurnaceView.class, tileEntity(SmokerBlockEntity::new, Blocks.SMOKER)));
|
||||
return asType(new MenuTypeData<>(FurnaceView.class, () -> new CraftBlockEntityInventoryViewBuilder<>(handle, Blocks.SMOKER, SmokerBlockEntity::new)));
|
||||
}
|
||||
if (menuType == MenuType.CARTOGRAPHY_TABLE) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(InventoryView.class, worldAccess(CartographyTableMenu::new)));
|
||||
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, CartographyTableMenu::new)));
|
||||
}
|
||||
if (menuType == MenuType.STONECUTTER) {
|
||||
return CraftMenus.asType(new MenuTypeData<>(StonecutterView.class, worldAccess(StonecutterMenu::new)));
|
||||
return asType(new MenuTypeData<>(StonecutterView.class, () -> new CraftAccessLocationInventoryViewBuilder<>(handle, StonecutterMenu::new)));
|
||||
}
|
||||
|
||||
return CraftMenus.asType(new MenuTypeData<>(InventoryView.class, CraftMenus.STANDARD));
|
||||
return asType(new MenuTypeData<>(InventoryView.class, () -> new CraftStandardInventoryViewBuilder<>(handle)));
|
||||
}
|
||||
|
||||
private static <V extends InventoryView> MenuTypeData<V> asType(MenuTypeData<?> data) {
|
||||
return (MenuTypeData<V>) data;
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <V extends InventoryView, B extends InventoryViewBuilder<V>> MenuTypeData<V, B> asType(final MenuTypeData<?, ?> data) {
|
||||
return (MenuTypeData<V, B>) data;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package org.bukkit.craftbukkit.inventory.view.builder;
|
||||
|
||||
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.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
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;
|
||||
|
||||
public abstract class CraftAbstractInventoryViewBuilder<V extends InventoryView> implements InventoryViewBuilder<V> {
|
||||
|
||||
protected final MenuType<?> handle;
|
||||
|
||||
protected boolean checkReachable = false;
|
||||
protected @MonotonicNonNull Component title = null;
|
||||
|
||||
public CraftAbstractInventoryViewBuilder(final MenuType<?> handle) {
|
||||
this.handle = handle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryViewBuilder<V> title(final Component title) {
|
||||
this.title = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@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");
|
||||
final ServerPlayer serverPlayer = (ServerPlayer) craftHuman.getHandle();
|
||||
final AbstractContainerMenu container = buildContainer(serverPlayer);
|
||||
container.checkReachable = this.checkReachable;
|
||||
container.setTitle(PaperAdventure.asVanilla(this.title));
|
||||
return (V) container.getBukkitView();
|
||||
}
|
||||
|
||||
protected abstract AbstractContainerMenu buildContainer(ServerPlayer player);
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package org.bukkit.craftbukkit.inventory.view.builder;
|
||||
|
||||
import com.google.common.base.Preconditions;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.craftbukkit.CraftWorld;
|
||||
import org.bukkit.craftbukkit.util.CraftLocation;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.view.builder.LocationInventoryViewBuilder;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public abstract class CraftAbstractLocationInventoryViewBuilder<V extends InventoryView> extends CraftAbstractInventoryViewBuilder<V> implements LocationInventoryViewBuilder<V> {
|
||||
|
||||
protected @Nullable Level world;
|
||||
protected @Nullable BlockPos position;
|
||||
|
||||
public CraftAbstractLocationInventoryViewBuilder(final MenuType<?> handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocationInventoryViewBuilder<V> title(final Component title) {
|
||||
return (LocationInventoryViewBuilder<V>) super.title(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocationInventoryViewBuilder<V> copy() {
|
||||
throw new UnsupportedOperationException("copy is not implemented on CraftAbstractLocationInventoryViewBuilder");
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocationInventoryViewBuilder<V> checkReachable(final boolean checkReachable) {
|
||||
super.checkReachable = checkReachable;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocationInventoryViewBuilder<V> location(final Location location) {
|
||||
Preconditions.checkArgument(location != null, "The provided location must not be null");
|
||||
Preconditions.checkArgument(location.getWorld() != null, "The provided location must be associated with a world");
|
||||
this.world = ((CraftWorld) location.getWorld()).getHandle();
|
||||
this.position = CraftLocation.toBlockPosition(location);
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package org.bukkit.craftbukkit.inventory.view.builder;
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
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 org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.view.builder.LocationInventoryViewBuilder;
|
||||
|
||||
public class CraftAccessLocationInventoryViewBuilder<V extends InventoryView> extends CraftAbstractLocationInventoryViewBuilder<V> {
|
||||
|
||||
private final CraftAccessContainerObjectBuilder containerBuilder;
|
||||
|
||||
public CraftAccessLocationInventoryViewBuilder(final MenuType<?> handle, final CraftAccessContainerObjectBuilder containerBuilder) {
|
||||
super(handle);
|
||||
this.containerBuilder = containerBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractContainerMenu buildContainer(final ServerPlayer player) {
|
||||
final ContainerLevelAccess access;
|
||||
if (super.position == null) {
|
||||
access = ContainerLevelAccess.create(player.level(), player.blockPosition());
|
||||
} else {
|
||||
access = ContainerLevelAccess.create(super.world, super.position);
|
||||
}
|
||||
|
||||
return this.containerBuilder.build(player.nextContainerCounter(), player.getInventory(), access);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocationInventoryViewBuilder<V> copy() {
|
||||
final CraftAccessLocationInventoryViewBuilder<V> copy = new CraftAccessLocationInventoryViewBuilder<>(this.handle, this.containerBuilder);
|
||||
copy.world = super.world;
|
||||
copy.position = super.position;
|
||||
copy.checkReachable = super.checkReachable;
|
||||
copy.title = title;
|
||||
return copy;
|
||||
}
|
||||
|
||||
public interface CraftAccessContainerObjectBuilder {
|
||||
AbstractContainerMenu build(final int syncId, final Inventory inventory, ContainerLevelAccess access);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,74 @@
|
|||
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.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.MenuConstructor;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.view.builder.LocationInventoryViewBuilder;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public class CraftBlockEntityInventoryViewBuilder<V extends InventoryView> extends CraftAbstractLocationInventoryViewBuilder<V> {
|
||||
|
||||
private final Block block;
|
||||
private final @Nullable CraftTileInventoryBuilder builder;
|
||||
|
||||
public CraftBlockEntityInventoryViewBuilder(final MenuType<?> handle, final Block block, final @Nullable CraftTileInventoryBuilder builder) {
|
||||
super(handle);
|
||||
this.block = block;
|
||||
this.builder = builder;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractContainerMenu buildContainer(final ServerPlayer player) {
|
||||
if (this.world == null) {
|
||||
this.world = player.level();
|
||||
}
|
||||
|
||||
if (this.position == null) {
|
||||
this.position = player.blockPosition();
|
||||
}
|
||||
|
||||
final BlockEntity entity = this.world.getBlockEntity(position);
|
||||
if (!(entity instanceof final MenuConstructor container)) {
|
||||
return buildFakeTile(player);
|
||||
}
|
||||
|
||||
final AbstractContainerMenu atBlock = container.createMenu(player.nextContainerCounter(), player.getInventory(), player);
|
||||
if (atBlock.getType() != super.handle) {
|
||||
return buildFakeTile(player);
|
||||
}
|
||||
|
||||
return atBlock;
|
||||
}
|
||||
|
||||
private AbstractContainerMenu buildFakeTile(final ServerPlayer player) {
|
||||
if (this.builder == null) {
|
||||
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);
|
||||
copy.world = this.world;
|
||||
copy.position = this.position;
|
||||
copy.checkReachable = super.checkReachable;
|
||||
copy.title = title;
|
||||
return copy;
|
||||
}
|
||||
|
||||
public interface CraftTileInventoryBuilder {
|
||||
MenuProvider build(BlockPos blockPosition, BlockState blockData);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
package org.bukkit.craftbukkit.inventory.view.builder;
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.MenuProvider;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.ChestBlock;
|
||||
import net.minecraft.world.level.block.DoubleBlockCombiner;
|
||||
import net.minecraft.world.level.block.entity.ChestBlockEntity;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.view.builder.LocationInventoryViewBuilder;
|
||||
|
||||
public class CraftDoubleChestInventoryViewBuilder<V extends InventoryView> extends CraftAbstractLocationInventoryViewBuilder<V> {
|
||||
|
||||
public CraftDoubleChestInventoryViewBuilder(final MenuType<?> handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractContainerMenu buildContainer(final ServerPlayer player) {
|
||||
if (super.world == null) {
|
||||
return handle.create(player.nextContainerCounter(), player.getInventory());
|
||||
}
|
||||
|
||||
final ChestBlock chest = (ChestBlock) Blocks.CHEST;
|
||||
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());
|
||||
}
|
||||
|
||||
final MenuProvider combined = result.apply(ChestBlock.MENU_PROVIDER_COMBINER).orElse(null);
|
||||
if (combined == null) {
|
||||
return handle.create(player.nextContainerCounter(), player.getInventory());
|
||||
}
|
||||
return combined.createMenu(player.nextContainerCounter(), player.getInventory(), player);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LocationInventoryViewBuilder<V> copy() {
|
||||
final CraftDoubleChestInventoryViewBuilder<V> copy = new CraftDoubleChestInventoryViewBuilder<>(super.handle);
|
||||
copy.world = this.world;
|
||||
copy.position = this.position;
|
||||
copy.checkReachable = super.checkReachable;
|
||||
copy.title = title;
|
||||
return copy;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,78 @@
|
|||
package org.bukkit.craftbukkit.inventory.view.builder;
|
||||
|
||||
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.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.inventory.MerchantMenu;
|
||||
import org.bukkit.craftbukkit.entity.CraftHumanEntity;
|
||||
import org.bukkit.craftbukkit.inventory.CraftMerchant;
|
||||
import org.bukkit.craftbukkit.inventory.CraftMerchantCustom;
|
||||
import org.bukkit.entity.HumanEntity;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.Merchant;
|
||||
import org.bukkit.inventory.view.builder.MerchantInventoryViewBuilder;
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
public class CraftMerchantInventoryViewBuilder<V extends InventoryView> extends CraftAbstractInventoryViewBuilder<V> implements MerchantInventoryViewBuilder<V> {
|
||||
|
||||
private net.minecraft.world.item.trading.@Nullable Merchant merchant;
|
||||
|
||||
public CraftMerchantInventoryViewBuilder(final MenuType<?> handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MerchantInventoryViewBuilder<V> title(final Component title) {
|
||||
return (MerchantInventoryViewBuilder<V>) super.title(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MerchantInventoryViewBuilder<V> merchant(final Merchant merchant) {
|
||||
this.merchant = ((CraftMerchant) merchant).getMerchant();
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MerchantInventoryViewBuilder<V> checkReachable(final boolean checkReachable) {
|
||||
super.checkReachable = checkReachable;
|
||||
return this;
|
||||
}
|
||||
|
||||
@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");
|
||||
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);
|
||||
}
|
||||
|
||||
container.checkReachable = super.checkReachable;
|
||||
container.setTitle(PaperAdventure.asVanilla(this.title));
|
||||
return (V) container.getBukkitView();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractContainerMenu buildContainer(final ServerPlayer player) {
|
||||
throw new UnsupportedOperationException("buildContainer is not supported for CraftMerchantInventoryViewBuilder");
|
||||
}
|
||||
|
||||
@Override
|
||||
public MerchantInventoryViewBuilder<V> copy() {
|
||||
final CraftMerchantInventoryViewBuilder<V> copy = new CraftMerchantInventoryViewBuilder<>(super.handle);
|
||||
copy.checkReachable = super.checkReachable;
|
||||
copy.merchant = this.merchant;
|
||||
copy.title = title;
|
||||
return copy;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package org.bukkit.craftbukkit.inventory.view.builder;
|
||||
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.inventory.AbstractContainerMenu;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import org.bukkit.inventory.InventoryView;
|
||||
import org.bukkit.inventory.view.builder.InventoryViewBuilder;
|
||||
|
||||
public class CraftStandardInventoryViewBuilder<V extends InventoryView> extends CraftAbstractInventoryViewBuilder<V> {
|
||||
|
||||
public CraftStandardInventoryViewBuilder(final MenuType<?> handle) {
|
||||
super(handle);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AbstractContainerMenu buildContainer(final ServerPlayer player) {
|
||||
return super.handle.create(player.nextContainerCounter(), player.getInventory());
|
||||
}
|
||||
|
||||
@Override
|
||||
public InventoryViewBuilder<V> copy() {
|
||||
final CraftStandardInventoryViewBuilder<V> copy = new CraftStandardInventoryViewBuilder<>(handle);
|
||||
copy.title = this.title;
|
||||
return copy;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
@NullMarked
|
||||
package org.bukkit.craftbukkit.inventory.view.builder;
|
||||
|
||||
import org.jspecify.annotations.NullMarked;
|
Loading…
Reference in a new issue