diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 21006883..fe964532 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -71,5 +71,6 @@ jobs: mvn paper-nms:init -pl nms/1_18_0 mvn paper-nms:init -pl nms/1_18_1 mvn paper-nms:init -pl nms/1_18_2 + mvn paper-nms:init -pl nms/1_19 - name: Build with Maven run: mvn -B package --file pom.xml diff --git a/IF/pom.xml b/IF/pom.xml index 6da0262c..83cac916 100644 --- a/IF/pom.xml +++ b/IF/pom.xml @@ -5,7 +5,7 @@ IF-parent com.github.stefvanschie.inventoryframework - 0.10.5 + 0.10.6 4.0.0 @@ -100,6 +100,12 @@ ${project.version} compile + + com.github.stefvanschie.inventoryframework + 1_19 + ${project.version} + compile + org.spigotmc spigot-api diff --git a/IF/src/main/java/com/github/stefvanschie/inventoryframework/gui/type/ChestGui.java b/IF/src/main/java/com/github/stefvanschie/inventoryframework/gui/type/ChestGui.java index fd2c46bc..33ba4c60 100644 --- a/IF/src/main/java/com/github/stefvanschie/inventoryframework/gui/type/ChestGui.java +++ b/IF/src/main/java/com/github/stefvanschie/inventoryframework/gui/type/ChestGui.java @@ -81,7 +81,7 @@ public ChestGui(int rows, @NotNull TextHolder title) { public void show(@NotNull HumanEntity humanEntity) { if (isDirty() || dirtyRows) { this.inventory = createInventory(); - this.dirtyRows = true; + this.dirtyRows = false; markChanges(); } diff --git a/IF/src/main/java/com/github/stefvanschie/inventoryframework/pane/Pane.java b/IF/src/main/java/com/github/stefvanschie/inventoryframework/pane/Pane.java index 381993fc..734cd36b 100644 --- a/IF/src/main/java/com/github/stefvanschie/inventoryframework/pane/Pane.java +++ b/IF/src/main/java/com/github/stefvanschie/inventoryframework/pane/Pane.java @@ -391,6 +391,12 @@ public static GuiItem loadItem(@NotNull Object instance, @NotNull Element elemen TextHolder.deserialize(item.getTextContent()) .asItemDisplayName(itemMeta); + itemStack.setItemMeta(itemMeta); + } else if (nodeName.equals("modeldata")) { + ItemMeta itemMeta = Objects.requireNonNull(itemStack.getItemMeta()); + + itemMeta.setCustomModelData(Integer.parseInt(item.getTextContent())); + itemStack.setItemMeta(itemMeta); } else if (nodeName.equals("skull") && itemStack.getItemMeta() instanceof SkullMeta) { SkullMeta skullMeta = (SkullMeta) itemStack.getItemMeta(); diff --git a/IF/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/CycleButton.java b/IF/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/CycleButton.java index 709d7028..93bc3c47 100644 --- a/IF/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/CycleButton.java +++ b/IF/src/main/java/com/github/stefvanschie/inventoryframework/pane/component/CycleButton.java @@ -61,6 +61,8 @@ public boolean click(@NotNull Gui gui, @NotNull InventoryComponent inventoryComp return false; } + int previousPosition = position; + position++; if (position == panes.size()) { @@ -69,7 +71,8 @@ public boolean click(@NotNull Gui gui, @NotNull InventoryComponent inventoryComp callOnClick(event); - Pane pane = panes.get(position); + //use the previous position, since that will have the pane we clicked on + Pane pane = panes.get(previousPosition); pane.click(gui, inventoryComponent, event, slot, paneOffsetX + x, paneOffsetY + y, length, height); diff --git a/IF/src/main/java/com/github/stefvanschie/inventoryframework/util/version/Version.java b/IF/src/main/java/com/github/stefvanschie/inventoryframework/util/version/Version.java index cd71bd4a..a3bf3087 100644 --- a/IF/src/main/java/com/github/stefvanschie/inventoryframework/util/version/Version.java +++ b/IF/src/main/java/com/github/stefvanschie/inventoryframework/util/version/Version.java @@ -80,7 +80,14 @@ public enum Version { * * @since 0.10.5 */ - V1_18_2; + V1_18_2, + + /** + * Version 1.19 + * + * @since 0.10.6 + */ + V1_19; /** * Gets the version currently being used. If the used version is not supported, an @@ -123,6 +130,8 @@ public static Version getVersion() { return V1_18_1; case "1.18.2": return V1_18_2; + case "1.19": + return V1_19; default: throw new UnsupportedVersionException("The server version provided is not supported"); } diff --git a/IF/src/main/java/com/github/stefvanschie/inventoryframework/util/version/VersionMatcher.java b/IF/src/main/java/com/github/stefvanschie/inventoryframework/util/version/VersionMatcher.java index c9830865..debac58c 100644 --- a/IF/src/main/java/com/github/stefvanschie/inventoryframework/util/version/VersionMatcher.java +++ b/IF/src/main/java/com/github/stefvanschie/inventoryframework/util/version/VersionMatcher.java @@ -252,6 +252,8 @@ public static StonecutterInventory newStonecutterInventory(@NotNull Version vers com.github.stefvanschie.inventoryframework.nms.v1_18_1.AnvilInventoryImpl.class); ANVIL_INVENTORIES.put(Version.V1_18_2, com.github.stefvanschie.inventoryframework.nms.v1_18_2.AnvilInventoryImpl.class); + ANVIL_INVENTORIES.put(Version.V1_19, + com.github.stefvanschie.inventoryframework.nms.v1_19.AnvilInventoryImpl.class); BEACON_INVENTORIES = new EnumMap<>(Version.class); BEACON_INVENTORIES.put(Version.V1_14, @@ -274,6 +276,8 @@ public static StonecutterInventory newStonecutterInventory(@NotNull Version vers com.github.stefvanschie.inventoryframework.nms.v1_18_1.BeaconInventoryImpl.class); BEACON_INVENTORIES.put(Version.V1_18_2, com.github.stefvanschie.inventoryframework.nms.v1_18_2.BeaconInventoryImpl.class); + BEACON_INVENTORIES.put(Version.V1_19, + com.github.stefvanschie.inventoryframework.nms.v1_19.BeaconInventoryImpl.class); CARTOGRAPHY_TABLE_INVENTORIES = new EnumMap<>(Version.class); CARTOGRAPHY_TABLE_INVENTORIES.put(Version.V1_14, @@ -296,6 +300,8 @@ public static StonecutterInventory newStonecutterInventory(@NotNull Version vers com.github.stefvanschie.inventoryframework.nms.v1_18_1.CartographyTableInventoryImpl.class); CARTOGRAPHY_TABLE_INVENTORIES.put(Version.V1_18_2, com.github.stefvanschie.inventoryframework.nms.v1_18_2.CartographyTableInventoryImpl.class); + CARTOGRAPHY_TABLE_INVENTORIES.put(Version.V1_19, + com.github.stefvanschie.inventoryframework.nms.v1_19.CartographyTableInventoryImpl.class); ENCHANTING_TABLE_INVENTORIES = new EnumMap<>(Version.class); ENCHANTING_TABLE_INVENTORIES.put(Version.V1_14, @@ -318,6 +324,8 @@ public static StonecutterInventory newStonecutterInventory(@NotNull Version vers com.github.stefvanschie.inventoryframework.nms.v1_18_1.EnchantingTableInventoryImpl.class); ENCHANTING_TABLE_INVENTORIES.put(Version.V1_18_2, com.github.stefvanschie.inventoryframework.nms.v1_18_2.EnchantingTableInventoryImpl.class); + ENCHANTING_TABLE_INVENTORIES.put(Version.V1_19, + com.github.stefvanschie.inventoryframework.nms.v1_19.EnchantingTableInventoryImpl.class); GRINDSTONE_INVENTORIES = new EnumMap<>(Version.class); GRINDSTONE_INVENTORIES.put(Version.V1_14, @@ -340,6 +348,8 @@ public static StonecutterInventory newStonecutterInventory(@NotNull Version vers com.github.stefvanschie.inventoryframework.nms.v1_18_1.GrindstoneInventoryImpl.class); GRINDSTONE_INVENTORIES.put(Version.V1_18_2, com.github.stefvanschie.inventoryframework.nms.v1_18_2.GrindstoneInventoryImpl.class); + GRINDSTONE_INVENTORIES.put(Version.V1_19, + com.github.stefvanschie.inventoryframework.nms.v1_19.GrindstoneInventoryImpl.class); MERCHANT_INVENTORIES = new EnumMap<>(Version.class); MERCHANT_INVENTORIES.put(Version.V1_14, @@ -362,6 +372,8 @@ public static StonecutterInventory newStonecutterInventory(@NotNull Version vers com.github.stefvanschie.inventoryframework.nms.v1_18_1.MerchantInventoryImpl.class); MERCHANT_INVENTORIES.put(Version.V1_18_2, com.github.stefvanschie.inventoryframework.nms.v1_18_2.MerchantInventoryImpl.class); + MERCHANT_INVENTORIES.put(Version.V1_19, + com.github.stefvanschie.inventoryframework.nms.v1_19.MerchantInventoryImpl.class); SMITHING_TABLE_INVENTORIES = new EnumMap<>(Version.class); SMITHING_TABLE_INVENTORIES.put(Version.V1_16_1, @@ -380,6 +392,8 @@ public static StonecutterInventory newStonecutterInventory(@NotNull Version vers com.github.stefvanschie.inventoryframework.nms.v1_18_1.SmithingTableInventoryImpl.class); SMITHING_TABLE_INVENTORIES.put(Version.V1_18_2, com.github.stefvanschie.inventoryframework.nms.v1_18_2.SmithingTableInventoryImpl.class); + SMITHING_TABLE_INVENTORIES.put(Version.V1_19, + com.github.stefvanschie.inventoryframework.nms.v1_19.SmithingTableInventoryImpl.class); STONECUTTER_INVENTORIES = new EnumMap<>(Version.class); STONECUTTER_INVENTORIES.put(Version.V1_14, @@ -402,5 +416,7 @@ public static StonecutterInventory newStonecutterInventory(@NotNull Version vers com.github.stefvanschie.inventoryframework.nms.v1_18_1.StonecutterInventoryImpl.class); STONECUTTER_INVENTORIES.put(Version.V1_18_2, com.github.stefvanschie.inventoryframework.nms.v1_18_2.StonecutterInventoryImpl.class); + STONECUTTER_INVENTORIES.put(Version.V1_19, + com.github.stefvanschie.inventoryframework.nms.v1_19.StonecutterInventoryImpl.class); } } diff --git a/README.md b/README.md index 75fa081f..d27a92dc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # IF Discord guild -*This framework works for Minecraft versions 1.14-1.18* +*This framework works for Minecraft versions 1.14-1.19* An inventory framework for managing GUIs @@ -14,7 +14,7 @@ To add this project as a dependency to your pom.xml, add the following to your p com.github.stefvanschie.inventoryframework IF - 0.10.5 + 0.10.6 ``` The project is in the Central Repository, so specifying a repository is not needed. @@ -50,7 +50,7 @@ Replace [YOUR PACKAGE] with the top-level package of your project. To add this project as a dependency for your Gradle project, make sure your `dependencies` section of your build.gradle looks like the following: ```Groovy dependencies { - compile 'com.github.stefvanschie.inventoryframework:IF:0.10.5' + compile 'com.github.stefvanschie.inventoryframework:IF:0.10.6' // ... } ``` @@ -128,6 +128,7 @@ mvn paper-nms:init -pl nms/1_17_1 mvn paper-nms:init -pl nms/1_18_0 mvn paper-nms:init -pl nms/1_18_1 mvn paper-nms:init -pl nms/1_18_2 +mvn paper-nms:init -pl nms/1_19 ``` Your environment is now set up correctly. To create a build, run the following inside the root folder of the project. diff --git a/adventure-support/pom.xml b/adventure-support/pom.xml index 89cf9fa4..a5521d71 100644 --- a/adventure-support/pom.xml +++ b/adventure-support/pom.xml @@ -5,7 +5,7 @@ IF-parent com.github.stefvanschie.inventoryframework - 0.10.5 + 0.10.6 4.0.0 diff --git a/nms/1_14/pom.xml b/nms/1_14/pom.xml index 33cffb51..ea9d4cb3 100644 --- a/nms/1_14/pom.xml +++ b/nms/1_14/pom.xml @@ -5,7 +5,7 @@ IF-parent com.github.stefvanschie.inventoryframework - 0.10.5 + 0.10.6 ../../pom.xml 4.0.0 diff --git a/nms/1_15/pom.xml b/nms/1_15/pom.xml index f7f50b56..5d318207 100644 --- a/nms/1_15/pom.xml +++ b/nms/1_15/pom.xml @@ -5,7 +5,7 @@ IF-parent com.github.stefvanschie.inventoryframework - 0.10.5 + 0.10.6 ../../pom.xml 4.0.0 diff --git a/nms/1_16_1/pom.xml b/nms/1_16_1/pom.xml index 6b3aba55..21ad9a5f 100644 --- a/nms/1_16_1/pom.xml +++ b/nms/1_16_1/pom.xml @@ -5,7 +5,7 @@ IF-parent com.github.stefvanschie.inventoryframework - 0.10.5 + 0.10.6 ../../pom.xml 4.0.0 diff --git a/nms/1_16_2-3/pom.xml b/nms/1_16_2-3/pom.xml index 9779b9b4..383f3dfe 100644 --- a/nms/1_16_2-3/pom.xml +++ b/nms/1_16_2-3/pom.xml @@ -5,7 +5,7 @@ IF-parent com.github.stefvanschie.inventoryframework - 0.10.5 + 0.10.6 ../../pom.xml 4.0.0 diff --git a/nms/1_16_4-5/pom.xml b/nms/1_16_4-5/pom.xml index a4c442fa..90265ab9 100644 --- a/nms/1_16_4-5/pom.xml +++ b/nms/1_16_4-5/pom.xml @@ -5,7 +5,7 @@ IF-parent com.github.stefvanschie.inventoryframework - 0.10.5 + 0.10.6 ../../pom.xml 4.0.0 diff --git a/nms/1_17_0/pom.xml b/nms/1_17_0/pom.xml index 99be8eda..f51760b4 100644 --- a/nms/1_17_0/pom.xml +++ b/nms/1_17_0/pom.xml @@ -5,7 +5,7 @@ IF-parent com.github.stefvanschie.inventoryframework - 0.10.5 + 0.10.6 ../../pom.xml 4.0.0 diff --git a/nms/1_17_1/pom.xml b/nms/1_17_1/pom.xml index 8e14cc36..3a02e871 100644 --- a/nms/1_17_1/pom.xml +++ b/nms/1_17_1/pom.xml @@ -5,7 +5,7 @@ IF-parent com.github.stefvanschie.inventoryframework - 0.10.5 + 0.10.6 ../../pom.xml 4.0.0 diff --git a/nms/1_18_0/pom.xml b/nms/1_18_0/pom.xml index ee140c16..f48b74b9 100644 --- a/nms/1_18_0/pom.xml +++ b/nms/1_18_0/pom.xml @@ -5,7 +5,7 @@ IF-parent com.github.stefvanschie.inventoryframework - 0.10.5 + 0.10.6 ../../pom.xml 4.0.0 diff --git a/nms/1_18_1/pom.xml b/nms/1_18_1/pom.xml index c4c9fb64..5bd4d221 100644 --- a/nms/1_18_1/pom.xml +++ b/nms/1_18_1/pom.xml @@ -5,7 +5,7 @@ IF-parent com.github.stefvanschie.inventoryframework - 0.10.5 + 0.10.6 ../../pom.xml 4.0.0 diff --git a/nms/1_18_2/pom.xml b/nms/1_18_2/pom.xml index 04a62c9b..40241565 100644 --- a/nms/1_18_2/pom.xml +++ b/nms/1_18_2/pom.xml @@ -5,7 +5,7 @@ IF-parent com.github.stefvanschie.inventoryframework - 0.10.5 + 0.10.6 ../../pom.xml 4.0.0 diff --git a/nms/1_19/pom.xml b/nms/1_19/pom.xml new file mode 100644 index 00000000..32c4bed6 --- /dev/null +++ b/nms/1_19/pom.xml @@ -0,0 +1,58 @@ + + + + IF-parent + com.github.stefvanschie.inventoryframework + 0.10.6 + ../../pom.xml + + 4.0.0 + + 1_19 + + + true + + + + + com.github.stefvanschie.inventoryframework + abstraction + ${project.version} + compile + + + ca.bkaw + paper-nms + 1.19-SNAPSHOT + provided + + + + + + + ca.bkaw + paper-nms-maven-plugin + 1.2.1 + + + process-classes + + remap + + + + + + + + + + bytecode.space + https://repo.bytecode.space/repository/maven-public/ + + + \ No newline at end of file diff --git a/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/AnvilInventoryImpl.java b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/AnvilInventoryImpl.java new file mode 100644 index 00000000..545d5512 --- /dev/null +++ b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/AnvilInventoryImpl.java @@ -0,0 +1,266 @@ +package com.github.stefvanschie.inventoryframework.nms.v1_19; + +import com.github.stefvanschie.inventoryframework.abstraction.AnvilInventory; +import com.github.stefvanschie.inventoryframework.adventuresupport.TextHolder; +import com.github.stefvanschie.inventoryframework.nms.v1_19.util.CustomInventoryUtil; +import com.github.stefvanschie.inventoryframework.nms.v1_19.util.TextHolderUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundContainerSetContentPacket; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.world.Container; +import net.minecraft.world.inventory.AnvilMenu; +import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import org.bukkit.Location; +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventory; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryAnvil; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryView; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Internal anvil inventory for 1.19 + * + * @since 0.10.6 + */ +public class AnvilInventoryImpl extends AnvilInventory { + + public AnvilInventoryImpl(@NotNull InventoryHolder inventoryHolder) { + super(inventoryHolder); + } + + @Override + public void openInventory(@NotNull Player player, @NotNull TextHolder title, + @Nullable org.bukkit.inventory.ItemStack[] items) { + int itemAmount = items.length; + + if (itemAmount != 3) { + throw new IllegalArgumentException( + "The amount of items for an anvil should be 3, but is '" + itemAmount + "'" + ); + } + + ServerPlayer serverPlayer = getServerPlayer(player); + ContainerAnvilImpl containerAnvil = new ContainerAnvilImpl(serverPlayer, items); + + serverPlayer.containerMenu = containerAnvil; + + int id = containerAnvil.containerId; + Component message = TextHolderUtil.toComponent(title); + + serverPlayer.connection.send(new ClientboundOpenScreenPacket(id, MenuType.ANVIL, message)); + + sendItems(player, items); + } + + @Override + public void sendItems(@NotNull Player player, @Nullable org.bukkit.inventory.ItemStack[] items) { + NonNullList nmsItems = CustomInventoryUtil.convertToNMSItems(items); + ServerPlayer serverPlayer = getServerPlayer(player); + int containerId = getContainerId(serverPlayer); + int state = serverPlayer.containerMenu.incrementStateId(); + ItemStack cursor = CraftItemStack.asNMSCopy(player.getItemOnCursor()); + ServerPlayerConnection playerConnection = getPlayerConnection(serverPlayer); + + playerConnection.send(new ClientboundContainerSetContentPacket(containerId, state, nmsItems, cursor)); + } + + @Override + public void sendFirstItem(@NotNull Player player, @Nullable org.bukkit.inventory.ItemStack item) { + ServerPlayer serverPlayer = getServerPlayer(player); + int containerId = getContainerId(serverPlayer); + ItemStack nmsItem = CraftItemStack.asNMSCopy(item); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(containerId, state, 0, nmsItem)); + } + + @Override + public void sendSecondItem(@NotNull Player player, @Nullable org.bukkit.inventory.ItemStack item) { + ServerPlayer serverPlayer = getServerPlayer(player); + int containerId = getContainerId(serverPlayer); + ItemStack nmsItem = CraftItemStack.asNMSCopy(item); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(containerId, state, 1, nmsItem)); + } + + @Override + public void sendResultItem(@NotNull Player player, @Nullable org.bukkit.inventory.ItemStack item) { + sendResultItem(player, CraftItemStack.asNMSCopy(item)); + } + + @Override + public void clearResultItem(@NotNull Player player) { + sendResultItem(player, ItemStack.EMPTY); + } + + @Override + public void setCursor(@NotNull Player player, @NotNull org.bukkit.inventory.ItemStack item) { + setCursor(player, CraftItemStack.asNMSCopy(item)); + } + + @Override + public void clearCursor(@NotNull Player player) { + ServerPlayer serverPlayer = getServerPlayer(player); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(-1, state, -1, ItemStack.EMPTY)); + } + + /** + * Sets the cursor of the given player + * + * @param player the player to set the cursor + * @param item the item to set the cursor to + * @since 0.10.6 + */ + private void setCursor(@NotNull Player player, @NotNull ItemStack item) { + ServerPlayer serverPlayer = getServerPlayer(player); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(-1, state, -1, item)); + } + + /** + * Sends the result item to the specified player with the given item + * + * @param player the player to send the result item to + * @param item the result item + * @since 0.10.6 + */ + private void sendResultItem(@NotNull Player player, @NotNull ItemStack item) { + ServerPlayer serverPlayer = getServerPlayer(player); + int containerId = getContainerId(serverPlayer); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(containerId, state, 2, item)); + } + + /** + * Gets the container id for the inventory view the player currently has open + * + * @param nmsPlayer the player to get the container id for + * @return the container id + * @since 0.10.6 + */ + @Contract(pure = true) + private int getContainerId(@NotNull net.minecraft.world.entity.player.Player nmsPlayer) { + return nmsPlayer.containerMenu.containerId; + } + + /** + * Gets the player connection for the specified player + * + * @param serverPlayer the player to get the player connection from + * @return the player connection + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayerConnection getPlayerConnection(@NotNull ServerPlayer serverPlayer) { + return serverPlayer.connection; + } + + /** + * Gets the server player associated to this player + * + * @param player the player to get the server player from + * @return the server player + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayer getServerPlayer(@NotNull Player player) { + return ((CraftPlayer) player).getHandle(); + } + + /** + * A custom container anvil for responding to item renaming + * + * @since 0.10.6 + */ + private class ContainerAnvilImpl extends AnvilMenu { + + /** + * The player for whom this anvil container is + */ + @NotNull + private final Player player; + + /** + * The internal bukkit entity for this container anvil + */ + @Nullable + private CraftInventoryView bukkitEntity; + + /** + * Creates a new custom anvil container for the specified player + * + * @param serverPlayer the player for who this anvil container is + * @since 0.10.6 + */ + public ContainerAnvilImpl(@NotNull ServerPlayer serverPlayer, + @Nullable org.bukkit.inventory.ItemStack[] items) { + super(serverPlayer.nextContainerCounter(), serverPlayer.getInventory(), + ContainerLevelAccess.create(serverPlayer.getCommandSenderWorld(), new BlockPos(0, 0, 0))); + + this.player = serverPlayer.getBukkitEntity(); + + inputSlots.setItem(0, CraftItemStack.asNMSCopy(items[0])); + inputSlots.setItem(1, CraftItemStack.asNMSCopy(items[1])); + resultSlots.setItem(0, CraftItemStack.asNMSCopy(items[2])); + } + + @NotNull + @Override + public CraftInventoryView getBukkitView() { + if (bukkitEntity == null) { + Location location = access.getLocation(); + CraftInventory inventory = new CraftInventoryAnvil(location, inputSlots, resultSlots, + this) { + @NotNull + @Contract(pure = true) + @Override + public InventoryHolder getHolder() { + return inventoryHolder; + } + }; + + bukkitEntity = new CraftInventoryView(player, inventory, this); + } + + return bukkitEntity; + } + + @Override + public void setItemName(@Nullable String name) { + text = name == null ? "" : name; + + sendResultItem(player, resultSlots.getItem(0)); + } + + @Contract(pure = true, value = "_ -> true") + @Override + public boolean stillValid(@Nullable net.minecraft.world.entity.player.Player nmsPlayer) { + return true; + } + + @Override + public void slotsChanged(Container container) {} + + @Override + public void removed(net.minecraft.world.entity.player.Player nmsPlayer) {} + } +} diff --git a/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/BeaconInventoryImpl.java b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/BeaconInventoryImpl.java new file mode 100644 index 00000000..793e7917 --- /dev/null +++ b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/BeaconInventoryImpl.java @@ -0,0 +1,199 @@ +package com.github.stefvanschie.inventoryframework.nms.v1_19; + +import com.github.stefvanschie.inventoryframework.abstraction.BeaconInventory; +import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundContainerSetContentPacket; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.world.Container; +import net.minecraft.world.inventory.BeaconMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventory; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryBeacon; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryView; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; + +/** + * Internal beacon inventory for 1.19 + * + * @since 0.10.6 + */ +public class BeaconInventoryImpl extends BeaconInventory { + + public BeaconInventoryImpl(@NotNull InventoryHolder inventoryHolder) { + super(inventoryHolder); + } + + @Override + public void openInventory(@NotNull Player player, @Nullable org.bukkit.inventory.ItemStack item) { + ServerPlayer serverPlayer = getServerPlayer(player); + ContainerBeaconImpl containerBeacon = new ContainerBeaconImpl(serverPlayer, item); + + serverPlayer.containerMenu = containerBeacon; + + int id = containerBeacon.containerId; + Component beacon = Component.literal("Beacon"); + + serverPlayer.connection.send(new ClientboundOpenScreenPacket(id, MenuType.BEACON, beacon)); + + sendItem(player, item); + } + + @Override + public void sendItem(@NotNull Player player, @Nullable org.bukkit.inventory.ItemStack item) { + NonNullList items = NonNullList.of( + ItemStack.EMPTY, //the first item doesn't count for some reason, so send a dummy item + CraftItemStack.asNMSCopy(item) + ); + + ServerPlayer serverPlayer = getServerPlayer(player); + int containerId = getContainerId(serverPlayer); + int state = serverPlayer.containerMenu.incrementStateId(); + ItemStack cursor = CraftItemStack.asNMSCopy(player.getItemOnCursor()); + ServerPlayerConnection playerConnection = getPlayerConnection(serverPlayer); + + playerConnection.send(new ClientboundContainerSetContentPacket(containerId, state, items, cursor)); + } + + @Override + public void clearCursor(@NotNull Player player) { + ServerPlayer serverPlayer = getServerPlayer(player); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(-1, state, -1, ItemStack.EMPTY)); + } + + /** + * Gets the container id for the inventory view the player currently has open + * + * @param nmsPlayer the player to get the container id for + * @return the container id + * @since 0.10.6 + */ + @Contract(pure = true) + private int getContainerId(@NotNull net.minecraft.world.entity.player.Player nmsPlayer) { + return nmsPlayer.containerMenu.containerId; + } + + /** + * Gets the player connection for the specified player + * + * @param serverPlayer the player to get the player connection from + * @return the player connection + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayerConnection getPlayerConnection(@NotNull ServerPlayer serverPlayer) { + return serverPlayer.connection; + } + + /** + * Gets the server player associated to this player + * + * @param player the player to get the server player from + * @return the server player + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayer getServerPlayer(@NotNull Player player) { + return ((CraftPlayer) player).getHandle(); + } + + /** + * A custom container beacon + * + * @since 0.10.6 + */ + private class ContainerBeaconImpl extends BeaconMenu { + + /** + * The player for this beacon container + */ + @NotNull + private final Player player; + + /** + * The internal bukkit entity for this container beacon + */ + @Nullable + private CraftInventoryView bukkitEntity; + + /** + * Field for accessing the beacon field + */ + @NotNull + private final Field beaconField; + + public ContainerBeaconImpl(@NotNull ServerPlayer serverPlayer, @Nullable org.bukkit.inventory.ItemStack item) { + super(serverPlayer.nextContainerCounter(), serverPlayer.getInventory()); + + this.player = serverPlayer.getBukkitEntity(); + + try { + //noinspection JavaReflectionMemberAccess + this.beaconField = BeaconMenu.class.getDeclaredField("r"); //beacon + this.beaconField.setAccessible(true); + } catch (NoSuchFieldException exception) { + throw new RuntimeException(exception); + } + + try { + ItemStack itemStack = CraftItemStack.asNMSCopy(item); + + ((Container) beaconField.get(this)).setItem(0, itemStack); + } catch (IllegalAccessException exception) { + throw new RuntimeException(exception); + } + } + + @NotNull + @Override + public CraftInventoryView getBukkitView() { + if (bukkitEntity == null) { + try { + CraftInventory inventory = new CraftInventoryBeacon((Container) beaconField.get(this)) { + @NotNull + @Contract(pure = true) + @Override + public InventoryHolder getHolder() { + return inventoryHolder; + } + }; + + bukkitEntity = new CraftInventoryView(player, inventory, this); + } catch (IllegalAccessException exception) { + throw new RuntimeException(exception); + } + } + + return bukkitEntity; + } + + @Contract(pure = true, value = "_ -> true") + @Override + public boolean stillValid(@Nullable net.minecraft.world.entity.player.Player nmsPlayer) { + return true; + } + + @Override + public void slotsChanged(Container container) {} + + @Override + public void removed(net.minecraft.world.entity.player.Player nmsPlayer) {} + + } +} diff --git a/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/CartographyTableInventoryImpl.java b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/CartographyTableInventoryImpl.java new file mode 100644 index 00000000..fef036b0 --- /dev/null +++ b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/CartographyTableInventoryImpl.java @@ -0,0 +1,213 @@ +package com.github.stefvanschie.inventoryframework.nms.v1_19; + +import com.github.stefvanschie.inventoryframework.abstraction.CartographyTableInventory; +import com.github.stefvanschie.inventoryframework.adventuresupport.TextHolder; +import com.github.stefvanschie.inventoryframework.nms.v1_19.util.CustomInventoryUtil; +import com.github.stefvanschie.inventoryframework.nms.v1_19.util.TextHolderUtil; +import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundContainerSetContentPacket; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.world.Container; +import net.minecraft.world.inventory.CartographyTableMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventory; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryCartography; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryView; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; + +/** + * Internal cartography table inventory for 1.19 + * + * @since 0.10.6 + */ +public class CartographyTableInventoryImpl extends CartographyTableInventory { + + public CartographyTableInventoryImpl(@NotNull InventoryHolder inventoryHolder) { + super(inventoryHolder); + } + + @Override + public void openInventory(@NotNull Player player, @NotNull TextHolder title, + @Nullable org.bukkit.inventory.ItemStack[] items) { + int itemAmount = items.length; + + if (itemAmount != 3) { + throw new IllegalArgumentException( + "The amount of items for a cartography table should be 3, but is '" + itemAmount + "'" + ); + } + + ServerPlayer serverPlayer = getServerPlayer(player); + ContainerCartographyTableImpl containerCartographyTable = new ContainerCartographyTableImpl( + serverPlayer, items + ); + + serverPlayer.containerMenu = containerCartographyTable; + + int id = containerCartographyTable.containerId; + Component message = TextHolderUtil.toComponent(title); + + serverPlayer.connection.send(new ClientboundOpenScreenPacket(id, MenuType.CARTOGRAPHY_TABLE, message)); + + sendItems(player, items); + } + + @Override + public void sendItems(@NotNull Player player, @Nullable org.bukkit.inventory.ItemStack[] items) { + NonNullList nmsItems = CustomInventoryUtil.convertToNMSItems(items); + ServerPlayer serverPlayer = getServerPlayer(player); + int containerId = getContainerId(serverPlayer); + int state = serverPlayer.containerMenu.incrementStateId(); + ItemStack cursor = CraftItemStack.asNMSCopy(player.getItemOnCursor()); + ServerPlayerConnection playerConnection = getPlayerConnection(serverPlayer); + + playerConnection.send(new ClientboundContainerSetContentPacket(containerId, state, nmsItems, cursor)); + } + + @Override + public void clearCursor(@NotNull Player player) { + ServerPlayer serverPlayer = getServerPlayer(player); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(-1, state, -1, ItemStack.EMPTY)); + } + + /** + * Gets the container id for the inventory view the player currently has open + * + * @param nmsPlayer the player to get the container id for + * @return the container id + * @since 0.10.6 + */ + @Contract(pure = true) + private int getContainerId(@NotNull net.minecraft.world.entity.player.Player nmsPlayer) { + return nmsPlayer.containerMenu.containerId; + } + + /** + * Gets the player connection for the specified player + * + * @param serverPlayer the player to get the player connection from + * @return the player connection + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayerConnection getPlayerConnection(@NotNull ServerPlayer serverPlayer) { + return serverPlayer.connection; + } + + /** + * Gets the server player associated to this player + * + * @param player the player to get the server player from + * @return the server player + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayer getServerPlayer(@NotNull Player player) { + return ((CraftPlayer) player).getHandle(); + } + + /** + * A custom container cartography table + * + * @since 0.10.6 + */ + private class ContainerCartographyTableImpl extends CartographyTableMenu { + + /** + * The player for this cartography table container + */ + @NotNull + private final Player player; + + /** + * The internal bukkit entity for this container cartography table + */ + @Nullable + private CraftInventoryView bukkitEntity; + + /** + * Field for accessing the result inventory field + */ + @NotNull + private final Field resultContainerField; + + public ContainerCartographyTableImpl(@NotNull ServerPlayer serverPlayer, + @Nullable org.bukkit.inventory.ItemStack[] items) { + super(serverPlayer.nextContainerCounter(), serverPlayer.getInventory()); + + this.player = serverPlayer.getBukkitEntity(); + + try { + //noinspection JavaReflectionMemberAccess + this.resultContainerField = CartographyTableMenu.class.getDeclaredField("u"); //resultContainer + this.resultContainerField.setAccessible(true); + } catch (NoSuchFieldException exception) { + throw new RuntimeException(exception); + } + + container.setItem(0, CraftItemStack.asNMSCopy(items[0])); + container.setItem(1, CraftItemStack.asNMSCopy(items[1])); + + getResultInventory().setItem(0, CraftItemStack.asNMSCopy(items[2])); + } + + @NotNull + @Override + public CraftInventoryView getBukkitView() { + if (bukkitEntity == null) { + CraftInventory inventory = new CraftInventoryCartography(super.container, getResultInventory()) { + @NotNull + @Contract(pure = true) + @Override + public InventoryHolder getHolder() { + return inventoryHolder; + } + }; + + bukkitEntity = new CraftInventoryView(player, inventory, this); + } + + return bukkitEntity; + } + + @Contract(pure = true, value = "_ -> true") + @Override + public boolean stillValid(@Nullable net.minecraft.world.entity.player.Player nmsPlayer) { + return true; + } + + @Override + public void slotsChanged(Container container) {} + + @Override + public void removed(net.minecraft.world.entity.player.Player nmsPlayer) {} + + @NotNull + @Contract(pure = true) + private Container getResultInventory() { + try { + return (Container) resultContainerField.get(this); + } catch (IllegalAccessException exception) { + throw new RuntimeException(exception); + } + } + + } +} diff --git a/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/EnchantingTableInventoryImpl.java b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/EnchantingTableInventoryImpl.java new file mode 100644 index 00000000..25b50c11 --- /dev/null +++ b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/EnchantingTableInventoryImpl.java @@ -0,0 +1,213 @@ +package com.github.stefvanschie.inventoryframework.nms.v1_19; + +import com.github.stefvanschie.inventoryframework.abstraction.EnchantingTableInventory; +import com.github.stefvanschie.inventoryframework.adventuresupport.TextHolder; +import com.github.stefvanschie.inventoryframework.nms.v1_19.util.TextHolderUtil; +import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundContainerSetContentPacket; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.world.Container; +import net.minecraft.world.inventory.EnchantmentMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventory; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryEnchanting; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryView; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; + +/** + * Internal enchanting table inventory for 1.19 + * + * @since 0.10.6 + */ +public class EnchantingTableInventoryImpl extends EnchantingTableInventory { + + public EnchantingTableInventoryImpl(@NotNull InventoryHolder inventoryHolder) { + super(inventoryHolder); + } + + @Override + public void openInventory(@NotNull Player player, @NotNull TextHolder title, + @Nullable org.bukkit.inventory.ItemStack[] items) { + int itemAmount = items.length; + + if (itemAmount != 2) { + throw new IllegalArgumentException( + "The amount of items for an enchanting table should be 2, but is '" + itemAmount + "'" + ); + } + + ServerPlayer serverPlayer = getServerPlayer(player); + ContainerEnchantingTableImpl containerEnchantmentTable = new ContainerEnchantingTableImpl(serverPlayer, items); + + serverPlayer.containerMenu = containerEnchantmentTable; + + int id = containerEnchantmentTable.containerId; + Component message = TextHolderUtil.toComponent(title); + + serverPlayer.connection.send(new ClientboundOpenScreenPacket(id, MenuType.ENCHANTMENT, message)); + + sendItems(player, items); + } + + @Override + public void sendItems(@NotNull Player player, @Nullable org.bukkit.inventory.ItemStack[] items) { + NonNullList nmsItems = NonNullList.of( + ItemStack.EMPTY, + CraftItemStack.asNMSCopy(items[0]), + CraftItemStack.asNMSCopy(items[1]) + ); + + ServerPlayer serverPlayer = getServerPlayer(player); + int containerId = getContainerId(serverPlayer); + int state = serverPlayer.containerMenu.incrementStateId(); + ItemStack cursor = CraftItemStack.asNMSCopy(player.getItemOnCursor()); + ServerPlayerConnection playerConnection = getPlayerConnection(serverPlayer); + + playerConnection.send(new ClientboundContainerSetContentPacket(containerId, state, nmsItems, cursor)); + } + + @Override + public void clearCursor(@NotNull Player player) { + ServerPlayer serverPlayer = getServerPlayer(player); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(-1, state, -1, ItemStack.EMPTY)); + } + + /** + * Gets the containerId id for the inventory view the player currently has open + * + * @param nmsPlayer the player to get the containerId id for + * @return the containerId id + * @since 0.10.6 + */ + @Contract(pure = true) + private int getContainerId(@NotNull net.minecraft.world.entity.player.Player nmsPlayer) { + return nmsPlayer.containerMenu.containerId; + } + + /** + * Gets the player connection for the specified player + * + * @param serverPlayer the player to get the player connection from + * @return the player connection + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayerConnection getPlayerConnection(@NotNull ServerPlayer serverPlayer) { + return serverPlayer.connection; + } + + /** + * Gets the server player associated to this player + * + * @param player the player to get the server player from + * @return the server player + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayer getServerPlayer(@NotNull Player player) { + return ((CraftPlayer) player).getHandle(); + } + + /** + * A custom container enchanting table + * + * @since 0.10.6 + */ + private class ContainerEnchantingTableImpl extends EnchantmentMenu { + + /** + * The player for this enchanting table container + */ + @NotNull + private final Player player; + + /** + * The internal bukkit entity for this container enchanting table + */ + @Nullable + private CraftInventoryView bukkitEntity; + + /** + * Field for accessing the enchant slots field + */ + @NotNull + private final Field enchantSlotsField; + + public ContainerEnchantingTableImpl(@NotNull ServerPlayer serverPlayer, + @Nullable org.bukkit.inventory.ItemStack[] items) { + super(serverPlayer.nextContainerCounter(), serverPlayer.getInventory()); + + this.player = serverPlayer.getBukkitEntity(); + + try { + //noinspection JavaReflectionMemberAccess + this.enchantSlotsField = EnchantmentMenu.class.getDeclaredField("n"); //enchantSlots + this.enchantSlotsField.setAccessible(true); + } catch (NoSuchFieldException exception) { + throw new RuntimeException(exception); + } + + try { + Container input = (Container) enchantSlotsField.get(this); + + input.setItem(0, CraftItemStack.asNMSCopy(items[0])); + input.setItem(1, CraftItemStack.asNMSCopy(items[1])); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + + @NotNull + @Override + public CraftInventoryView getBukkitView() { + if (bukkitEntity == null) { + try { + CraftInventory inventory = new CraftInventoryEnchanting((Container) enchantSlotsField.get(this)) { + @NotNull + @Contract(pure = true) + @Override + public InventoryHolder getHolder() { + return inventoryHolder; + } + }; + + bukkitEntity = new CraftInventoryView(player, inventory, this); + } catch (IllegalAccessException exception) { + exception.printStackTrace(); + } + } + + return bukkitEntity; + } + + @Contract(pure = true, value = "_ -> true") + @Override + public boolean stillValid(@Nullable net.minecraft.world.entity.player.Player nmsPlayer) { + return true; + } + + @Override + public void slotsChanged(Container container) {} + + @Override + public void removed(net.minecraft.world.entity.player.Player nmsPlayer) {} + + } +} diff --git a/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/GrindstoneInventoryImpl.java b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/GrindstoneInventoryImpl.java new file mode 100644 index 00000000..933d50c5 --- /dev/null +++ b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/GrindstoneInventoryImpl.java @@ -0,0 +1,247 @@ +package com.github.stefvanschie.inventoryframework.nms.v1_19; + +import com.github.stefvanschie.inventoryframework.abstraction.GrindstoneInventory; +import com.github.stefvanschie.inventoryframework.adventuresupport.TextHolder; +import com.github.stefvanschie.inventoryframework.nms.v1_19.util.CustomInventoryUtil; +import com.github.stefvanschie.inventoryframework.nms.v1_19.util.TextHolderUtil; +import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundContainerSetContentPacket; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.world.Container; +import net.minecraft.world.inventory.GrindstoneMenu; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventory; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryGrindstone; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryView; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; + +/** + * Internal grindstone inventory for 1.19 + * + * @since 0.10.6 + */ +public class GrindstoneInventoryImpl extends GrindstoneInventory { + + public GrindstoneInventoryImpl(@NotNull InventoryHolder inventoryHolder) { + super(inventoryHolder); + } + + @Override + public void openInventory(@NotNull Player player, @NotNull TextHolder title, + @Nullable org.bukkit.inventory.ItemStack[] items) { + int itemAmount = items.length; + + if (itemAmount != 3) { + throw new IllegalArgumentException( + "The amount of items for a grindstone should be 3, but is '" + itemAmount + "'" + ); + } + + ServerPlayer serverPlayer = getServerPlayer(player); + ContainerGrindstoneImpl containerGrindstone = new ContainerGrindstoneImpl(serverPlayer, items); + + serverPlayer.containerMenu = containerGrindstone; + + int id = containerGrindstone.containerId; + Component message = TextHolderUtil.toComponent(title); + + serverPlayer.connection.send(new ClientboundOpenScreenPacket(id, MenuType.GRINDSTONE, message)); + + sendItems(player, items, player.getItemOnCursor()); + } + + @Override + public void sendItems(@NotNull Player player, @Nullable org.bukkit.inventory.ItemStack[] items, + @Nullable org.bukkit.inventory.ItemStack cursor) { + if (cursor == null) { + throw new IllegalArgumentException("Cursor may not be null on version 1.17.1"); + } + + NonNullList nmsItems = CustomInventoryUtil.convertToNMSItems(items); + ServerPlayer serverPlayer = getServerPlayer(player); + int containerId = getContainerId(serverPlayer); + int state = serverPlayer.containerMenu.incrementStateId(); + ItemStack nmsCursor = CraftItemStack.asNMSCopy(cursor); + ServerPlayerConnection playerConnection = getPlayerConnection(serverPlayer); + + playerConnection.send(new ClientboundContainerSetContentPacket(containerId, state, nmsItems, nmsCursor)); + } + + @Override + public void clearCursor(@NotNull Player player) { + ServerPlayer serverPlayer = getServerPlayer(player); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(-1, state, -1, ItemStack.EMPTY)); + } + + /** + * Gets the containerId id for the inventory view the player currently has open + * + * @param nmsPlayer the player to get the containerId id for + * @return the containerId id + * @since 0.10.6 + */ + @Contract(pure = true) + private int getContainerId(@NotNull net.minecraft.world.entity.player.Player nmsPlayer) { + return nmsPlayer.containerMenu.containerId; + } + + /** + * Gets the player connection for the specified player + * + * @param serverPlayer the player to get the player connection from + * @return the player connection + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayerConnection getPlayerConnection(@NotNull ServerPlayer serverPlayer) { + return serverPlayer.connection; + } + + /** + * Gets the server player associated to this player + * + * @param player the player to get the server player from + * @return the server player + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayer getServerPlayer(@NotNull Player player) { + return ((CraftPlayer) player).getHandle(); + } + + /** + * A custom container grindstone + * + * @since 0.10.6 + */ + private class ContainerGrindstoneImpl extends GrindstoneMenu { + + /** + * The player for this grindstone container + */ + @NotNull + private final Player player; + + /** + * The internal bukkit entity for this container grindstone + */ + @Nullable + private CraftInventoryView bukkitEntity; + + /** + * Field for accessing the craft inventory field + */ + @NotNull + private final Field repairSlotsField; + + /** + * Field for accessing the result inventory field + */ + @NotNull + private final Field resultSlotsField; + + public ContainerGrindstoneImpl(@NotNull ServerPlayer serverPlayer, + @Nullable org.bukkit.inventory.ItemStack[] items) { + super(serverPlayer.nextContainerCounter(), serverPlayer.getInventory()); + + this.player = serverPlayer.getBukkitEntity(); + + try { + //noinspection JavaReflectionMemberAccess + this.repairSlotsField = GrindstoneMenu.class.getDeclaredField("t"); //repairSlots + this.repairSlotsField.setAccessible(true); + + //noinspection JavaReflectionMemberAccess + this.resultSlotsField = GrindstoneMenu.class.getDeclaredField("s"); //resultSlots + this.resultSlotsField.setAccessible(true); + } catch (NoSuchFieldException exception) { + throw new RuntimeException(exception); + } + + getCraftInventory().setItem(0, CraftItemStack.asNMSCopy(items[0])); + getCraftInventory().setItem(1, CraftItemStack.asNMSCopy(items[1])); + + getResultInventory().setItem(2, CraftItemStack.asNMSCopy(items[2])); + } + + @NotNull + @Override + public CraftInventoryView getBukkitView() { + if (bukkitEntity == null) { + CraftInventory inventory = new CraftInventoryGrindstone(getCraftInventory(), getResultInventory()) { + @NotNull + @Contract(pure = true) + @Override + public InventoryHolder getHolder() { + return inventoryHolder; + } + }; + + bukkitEntity = new CraftInventoryView(player, inventory, this); + } + + return bukkitEntity; + } + + @Contract(pure = true, value = "_ -> true") + @Override + public boolean stillValid(@Nullable net.minecraft.world.entity.player.Player nmsPlayer) { + return true; + } + + @Override + public void slotsChanged(Container container) {} + + @Override + public void removed(net.minecraft.world.entity.player.Player nmsPlayer) {} + + /** + * Gets the craft inventory + * + * @return the craft inventory + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private Container getCraftInventory() { + try { + return (Container) repairSlotsField.get(this); + } catch (IllegalAccessException exception) { + throw new RuntimeException(exception); + } + } + + /** + * Gets the result inventory + * + * @return the result inventory + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private Container getResultInventory() { + try { + return (Container) resultSlotsField.get(this); + } catch (IllegalAccessException exception) { + throw new RuntimeException(exception); + } + } + } +} diff --git a/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/MerchantInventoryImpl.java b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/MerchantInventoryImpl.java new file mode 100644 index 00000000..d93a58a3 --- /dev/null +++ b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/MerchantInventoryImpl.java @@ -0,0 +1,97 @@ +package com.github.stefvanschie.inventoryframework.nms.v1_19; + +import com.github.stefvanschie.inventoryframework.abstraction.MerchantInventory; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.item.trading.MerchantOffers; +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.MerchantRecipe; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.util.List; +import java.util.Map; + +/** + * Internal merchant inventory for 1.19 + * + * @since 0.10.6 + */ +public class MerchantInventoryImpl extends MerchantInventory { + + @Override + public void sendMerchantOffers(@NotNull Player player, + @NotNull List> trades, + int level, int experience) { + MerchantOffers offers = new MerchantOffers(); + + for (Map.Entry entry : trades) { + MerchantRecipe recipe = entry.getKey(); + List ingredients = recipe.getIngredients(); + + if (ingredients.size() < 1) { + throw new IllegalStateException("Merchant recipe has no ingredients"); + } + + ItemStack itemA = ingredients.get(0); + ItemStack itemB = null; + + if (ingredients.size() >= 2) { + itemB = ingredients.get(1); + } + + net.minecraft.world.item.ItemStack nmsItemA = CraftItemStack.asNMSCopy(itemA); + net.minecraft.world.item.ItemStack nmsItemB = net.minecraft.world.item.ItemStack.EMPTY; + net.minecraft.world.item.ItemStack nmsItemResult = CraftItemStack.asNMSCopy(recipe.getResult()); + + if (itemB != null) { + nmsItemB = CraftItemStack.asNMSCopy(itemB); + } + + int uses = recipe.getUses(); + int maxUses = recipe.getMaxUses(); + int exp = recipe.getVillagerExperience(); + float multiplier = recipe.getPriceMultiplier(); + + MerchantOffer merchantOffer = new MerchantOffer( + nmsItemA, nmsItemB, nmsItemResult, uses, maxUses, exp, multiplier + ); + merchantOffer.setSpecialPriceDiff(entry.getValue()); + + offers.add(merchantOffer); + } + + ServerPlayer serverPlayer = getServerPlayer(player); + int containerId = getContainerId(serverPlayer); + + serverPlayer.sendMerchantOffers(containerId, offers, level, experience, true, false); + } + + /** + * Gets the server player associated to this player + * + * @param player the player to get the server player from + * @return the server player + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayer getServerPlayer(@NotNull Player player) { + return ((CraftPlayer) player).getHandle(); + } + + /** + * Gets the containerId id for the inventory view the player currently has open + * + * @param nmsPlayer the player to get the containerId id for + * @return the containerId id + * @since 0.10.6 + */ + @Contract(pure = true) + private int getContainerId(@NotNull net.minecraft.world.entity.player.Player nmsPlayer) { + return nmsPlayer.containerMenu.containerId; + } +} diff --git a/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/SmithingTableInventoryImpl.java b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/SmithingTableInventoryImpl.java new file mode 100644 index 00000000..c317dae8 --- /dev/null +++ b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/SmithingTableInventoryImpl.java @@ -0,0 +1,251 @@ +package com.github.stefvanschie.inventoryframework.nms.v1_19; + +import com.github.stefvanschie.inventoryframework.abstraction.SmithingTableInventory; +import com.github.stefvanschie.inventoryframework.adventuresupport.TextHolder; +import com.github.stefvanschie.inventoryframework.nms.v1_19.util.CustomInventoryUtil; +import com.github.stefvanschie.inventoryframework.nms.v1_19.util.TextHolderUtil; +import net.minecraft.core.BlockPos; +import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundContainerSetContentPacket; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.world.Container; +import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.SmithingMenu; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventory; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventorySmithing; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryView; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * Internal smithing table inventory for 1.19 + * + * @since 0.10.6 + */ +public class SmithingTableInventoryImpl extends SmithingTableInventory { + + public SmithingTableInventoryImpl(@NotNull InventoryHolder inventoryHolder) { + super(inventoryHolder); + } + + @Override + public void openInventory(@NotNull Player player, @NotNull TextHolder title, + @Nullable org.bukkit.inventory.ItemStack[] items) { + int itemAmount = items.length; + + if (itemAmount != 3) { + throw new IllegalArgumentException( + "The amount of items for a smithing table should be 3, but is '" + itemAmount + "'" + ); + } + + ServerPlayer serverPlayer = getServerPlayer(player); + ContainerSmithingTableImpl containerSmithingTable = new ContainerSmithingTableImpl(serverPlayer, items); + + serverPlayer.containerMenu = containerSmithingTable; + + int id = containerSmithingTable.containerId; + Component message = TextHolderUtil.toComponent(title); + + serverPlayer.connection.send(new ClientboundOpenScreenPacket(id, MenuType.SMITHING, message)); + + sendItems(player, items, player.getItemOnCursor()); + } + + @Override + public void sendItems(@NotNull Player player, @Nullable org.bukkit.inventory.ItemStack[] items, + @Nullable org.bukkit.inventory.ItemStack cursor) { + NonNullList nmsItems = CustomInventoryUtil.convertToNMSItems(items); + ServerPlayer serverPlayer = getServerPlayer(player); + int containerId = getContainerId(serverPlayer); + int state = serverPlayer.containerMenu.incrementStateId(); + ItemStack nmsCursor = CraftItemStack.asNMSCopy(cursor); + ServerPlayerConnection playerConnection = getPlayerConnection(serverPlayer); + + playerConnection.send(new ClientboundContainerSetContentPacket(containerId, state, nmsItems, nmsCursor)); + } + + @Override + public void sendFirstItem(@NotNull Player player, @Nullable org.bukkit.inventory.ItemStack item) { + ServerPlayer serverPlayer = getServerPlayer(player); + ItemStack nmsItem = CraftItemStack.asNMSCopy(item); + int containerId = getContainerId(serverPlayer); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(containerId, state, 0, nmsItem)); + } + + @Override + public void sendSecondItem(@NotNull Player player, @Nullable org.bukkit.inventory.ItemStack item) { + ServerPlayer serverPlayer = getServerPlayer(player); + ItemStack nmsItem = CraftItemStack.asNMSCopy(item); + int containerId = getContainerId(serverPlayer); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(containerId, state, 1, nmsItem)); + } + + @Override + public void sendResultItem(@NotNull Player player, @Nullable org.bukkit.inventory.ItemStack item) { + sendResultItem(player, CraftItemStack.asNMSCopy(item)); + } + + @Override + public void clearResultItem(@NotNull Player player) { + sendResultItem(player, ItemStack.EMPTY); + } + + @Override + public void setCursor(@NotNull Player player, @NotNull org.bukkit.inventory.ItemStack item) { + setCursor(player, CraftItemStack.asNMSCopy(item)); + } + + @Override + public void clearCursor(@NotNull Player player) { + ServerPlayer serverPlayer = getServerPlayer(player); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(-1, state, -1, ItemStack.EMPTY)); + } + + /** + * Sets the cursor of the given player + * + * @param player the player to set the cursor + * @param item the item to set the cursor to + * @since 0.10.6 + */ + private void setCursor(@NotNull Player player, @NotNull ItemStack item) { + ServerPlayer serverPlayer = getServerPlayer(player); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(-1, state, -1, item)); + } + + /** + * Sends the result item to the specified player with the given item + * + * @param player the player to send the result item to + * @param item the result item + * @since 0.10.6 + */ + private void sendResultItem(@NotNull Player player, @NotNull ItemStack item) { + ServerPlayer serverPlayer = getServerPlayer(player); + int containerId = getContainerId(serverPlayer); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(containerId, state, 2, item)); + } + + /** + * Gets the container id for the inventory view the player currently has open + * + * @param nmsPlayer the player to get the container id for + * @return the container id + * @since 0.10.6 + */ + @Contract(pure = true) + private int getContainerId(@NotNull net.minecraft.world.entity.player.Player nmsPlayer) { + return nmsPlayer.containerMenu.containerId; + } + + /** + * Gets the player connection for the specified player + * + * @param serverPlayer the player to get the player connection from + * @return the player connection + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayerConnection getPlayerConnection(@NotNull ServerPlayer serverPlayer) { + return serverPlayer.connection; + } + + /** + * Gets the server player associated to this player + * + * @param player the player to get the server player from + * @return the server player + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayer getServerPlayer(@NotNull Player player) { + return ((CraftPlayer) player).getHandle(); + } + + /** + * A custom container smithing table + * + * @since 0.10.6 + */ + private class ContainerSmithingTableImpl extends SmithingMenu { + + /** + * The player for this smithing table container + */ + @NotNull + private final Player player; + + /** + * The internal bukkit entity for this container smithing table + */ + @Nullable + private CraftInventoryView bukkitEntity; + + public ContainerSmithingTableImpl(@NotNull ServerPlayer serverPlayer, + @Nullable org.bukkit.inventory.ItemStack[] items) { + super(serverPlayer.nextContainerCounter(), serverPlayer.getInventory(), + ContainerLevelAccess.create(serverPlayer.getCommandSenderWorld(), new BlockPos(0, 0, 0))); + + this.player = serverPlayer.getBukkitEntity(); + + inputSlots.setItem(0, CraftItemStack.asNMSCopy(items[0])); + inputSlots.setItem(1, CraftItemStack.asNMSCopy(items[1])); + resultSlots.setItem(0, CraftItemStack.asNMSCopy(items[2])); + } + + @NotNull + @Override + public CraftInventoryView getBukkitView() { + if (bukkitEntity == null) { + CraftInventory inventory = new CraftInventorySmithing(access.getLocation(), inputSlots, resultSlots) { + @NotNull + @Contract(pure = true) + @Override + public InventoryHolder getHolder() { + return inventoryHolder; + } + }; + + bukkitEntity = new CraftInventoryView(player, inventory, this); + } + + return bukkitEntity; + } + + @Contract(pure = true, value = "_ -> true") + @Override + public boolean stillValid(@Nullable net.minecraft.world.entity.player.Player nmsPlayer) { + return true; + } + + @Override + public void slotsChanged(Container container) {} + + @Override + public void removed(net.minecraft.world.entity.player.Player nmsPlayer) {} + } +} diff --git a/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/StonecutterInventoryImpl.java b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/StonecutterInventoryImpl.java new file mode 100644 index 00000000..eafd1cbb --- /dev/null +++ b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/StonecutterInventoryImpl.java @@ -0,0 +1,219 @@ +package com.github.stefvanschie.inventoryframework.nms.v1_19; + +import com.github.stefvanschie.inventoryframework.abstraction.StonecutterInventory; +import com.github.stefvanschie.inventoryframework.adventuresupport.TextHolder; +import com.github.stefvanschie.inventoryframework.nms.v1_19.util.TextHolderUtil; +import net.minecraft.core.NonNullList; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ClientboundContainerSetContentPacket; +import net.minecraft.network.protocol.game.ClientboundContainerSetSlotPacket; +import net.minecraft.network.protocol.game.ClientboundOpenScreenPacket; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.server.network.ServerPlayerConnection; +import net.minecraft.world.Container; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.inventory.StonecutterMenu; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventory; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryStonecutter; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftInventoryView; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; +import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; + +/** + * Internal stonecutter inventory for 1.19 + * + * @since 0.10.6 + */ +public class StonecutterInventoryImpl extends StonecutterInventory { + + public StonecutterInventoryImpl(@NotNull InventoryHolder inventoryHolder) { + super(inventoryHolder); + } + + @Override + public void openInventory(@NotNull Player player, @NotNull TextHolder title, + @Nullable org.bukkit.inventory.ItemStack[] items) { + int itemAmount = items.length; + + if (itemAmount != 2) { + throw new IllegalArgumentException( + "The amount of items for a stonecutter should be 2, but is '" + itemAmount + "'" + ); + } + + ServerPlayer serverPlayer = getServerPlayer(player); + ContainerStonecutterImpl containerEnchantmentTable = new ContainerStonecutterImpl(serverPlayer, items); + + serverPlayer.containerMenu = containerEnchantmentTable; + + int id = containerEnchantmentTable.containerId; + Component message = TextHolderUtil.toComponent(title); + ClientboundOpenScreenPacket packet = new ClientboundOpenScreenPacket(id, MenuType.STONECUTTER, message); + + serverPlayer.connection.send(packet); + + sendItems(player, items); + } + + @Override + public void sendItems(@NotNull Player player, @Nullable org.bukkit.inventory.ItemStack[] items) { + NonNullList nmsItems = NonNullList.of( + ItemStack.EMPTY, + CraftItemStack.asNMSCopy(items[0]), + CraftItemStack.asNMSCopy(items[1]) + ); + + ServerPlayer serverPlayer = getServerPlayer(player); + int containerId = getContainerId(serverPlayer); + int state = serverPlayer.containerMenu.incrementStateId(); + ItemStack cursor = CraftItemStack.asNMSCopy(player.getItemOnCursor()); + ServerPlayerConnection playerConnection = getPlayerConnection(serverPlayer); + + playerConnection.send(new ClientboundContainerSetContentPacket(containerId, state, nmsItems, cursor)); + } + + @Override + public void clearCursor(@NotNull Player player) { + ServerPlayer serverPlayer = getServerPlayer(player); + int state = serverPlayer.containerMenu.incrementStateId(); + + getPlayerConnection(serverPlayer).send(new ClientboundContainerSetSlotPacket(-1, state, -1, ItemStack.EMPTY)); + } + + /** + * Gets the container id for the inventory view the player currently has open + * + * @param nmsPlayer the player to get the container id for + * @return the container id + * @since 0.10.6 + */ + @Contract(pure = true) + private int getContainerId(@NotNull net.minecraft.world.entity.player.Player nmsPlayer) { + return nmsPlayer.containerMenu.containerId; + } + + /** + * Gets the player connection for the specified player + * + * @param serverPlayer the player to get the player connection from + * @return the player connection + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayerConnection getPlayerConnection(@NotNull ServerPlayer serverPlayer) { + return serverPlayer.connection; + } + + /** + * Gets the server player associated to this player + * + * @param player the player to get the server player from + * @return the server player + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private ServerPlayer getServerPlayer(@NotNull Player player) { + return ((CraftPlayer) player).getHandle(); + } + + /** + * A custom container enchanting table + * + * @since 0.10.6 + */ + private class ContainerStonecutterImpl extends StonecutterMenu { + + /** + * The player for this enchanting table container + */ + @NotNull + private final Player player; + + /** + * The internal bukkit entity for this container enchanting table + */ + @Nullable + private CraftInventoryView bukkitEntity; + + /** + * Field for accessing the result inventory field + */ + @NotNull + private final Field resultContainerField; + + public ContainerStonecutterImpl(@NotNull ServerPlayer entityPlayer, + @Nullable org.bukkit.inventory.ItemStack[] items) { + super(entityPlayer.nextContainerCounter(), entityPlayer.getInventory()); + + this.player = entityPlayer.getBukkitEntity(); + + try { + //noinspection JavaReflectionMemberAccess + this.resultContainerField = StonecutterMenu.class.getDeclaredField("A"); //resultContainer + this.resultContainerField.setAccessible(true); + } catch (NoSuchFieldException exception) { + throw new RuntimeException(exception); + } + + container.setItem(0, CraftItemStack.asNMSCopy(items[0])); + getResultInventory().setItem(0, CraftItemStack.asNMSCopy(items[1])); + } + + @NotNull + @Override + public CraftInventoryView getBukkitView() { + if (bukkitEntity == null) { + CraftInventory inventory = new CraftInventoryStonecutter(this.container, getResultInventory()) { + @NotNull + @Contract(pure = true) + @Override + public InventoryHolder getHolder() { + return inventoryHolder; + } + }; + + bukkitEntity = new CraftInventoryView(player, inventory, this); + } + + return bukkitEntity; + } + + @Contract(pure = true, value = "_ -> true") + @Override + public boolean stillValid(@Nullable net.minecraft.world.entity.player.Player nmsPlayer) { + return true; + } + + @Override + public void slotsChanged(Container container) {} + + @Override + public void removed(net.minecraft.world.entity.player.Player nmsPlayer) {} + + /** + * Gets the result inventory + * + * @return the result inventory + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + public Container getResultInventory() { + try { + return (Container) resultContainerField.get(this); + } catch (IllegalAccessException exception) { + throw new RuntimeException(exception); + } + } + } +} diff --git a/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/util/CustomInventoryUtil.java b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/util/CustomInventoryUtil.java new file mode 100644 index 00000000..30d58cdd --- /dev/null +++ b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/util/CustomInventoryUtil.java @@ -0,0 +1,41 @@ +package com.github.stefvanschie.inventoryframework.nms.v1_19.util; + +import net.minecraft.core.NonNullList; +import net.minecraft.world.item.ItemStack; +import org.bukkit.craftbukkit.v1_19_R1.inventory.CraftItemStack; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/** + * A utility class for custom inventories + * + * @since 0.10.6 + */ +public final class CustomInventoryUtil { + + /** + * A private constructor to prevent construction. + */ + private CustomInventoryUtil() {} + + /** + * Converts an array of Bukkit items into a non null list of NMS items. The returned list is modifiable. If no items + * were specified, this returns an empty list. + * + * @param items the items to convert + * @return a list of converted items + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + public static NonNullList convertToNMSItems(@Nullable org.bukkit.inventory.ItemStack @NotNull [] items) { + NonNullList nmsItems = NonNullList.create(); + + for (org.bukkit.inventory.ItemStack item : items) { + nmsItems.add(CraftItemStack.asNMSCopy(item)); + } + + return nmsItems; + } +} diff --git a/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/util/TextHolderUtil.java b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/util/TextHolderUtil.java new file mode 100644 index 00000000..c3df6407 --- /dev/null +++ b/nms/1_19/src/main/java/com/github/stefvanschie/inventoryframework/nms/v1_19/util/TextHolderUtil.java @@ -0,0 +1,65 @@ +package com.github.stefvanschie.inventoryframework.nms.v1_19.util; + +import com.github.stefvanschie.inventoryframework.adventuresupport.ComponentHolder; +import com.github.stefvanschie.inventoryframework.adventuresupport.StringHolder; +import com.github.stefvanschie.inventoryframework.adventuresupport.TextHolder; +import net.minecraft.network.chat.Component; +import org.jetbrains.annotations.Contract; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +/** + * A utility class for adding {@link TextHolder} support. + * + * @since 0.10.6 + */ +public final class TextHolderUtil { + + private TextHolderUtil() { + //private constructor to prevent construction + } + + /** + * Converts the specified value to a vanilla component. + * + * @param holder the value to convert + * @return the value as a vanilla component + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + public static Component toComponent(@NotNull TextHolder holder) { + if (holder instanceof StringHolder) { + return toComponent((StringHolder) holder); + } else { + return toComponent((ComponentHolder) holder); + } + } + + /** + * Converts the specified legacy string holder to a vanilla component. + * + * @param holder the value to convert + * @return the value as a vanilla component + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private static Component toComponent(@NotNull StringHolder holder) { + return Component.literal(holder.asLegacyString()); + } + + /** + * Converts the specified Adventure component holder to a vanilla component. + * + * @param holder the value to convert + * @return the value as a vanilla component + * @since 0.10.6 + */ + @NotNull + @Contract(pure = true) + private static Component toComponent(@NotNull ComponentHolder holder) { + return Objects.requireNonNull(Component.Serializer.fromJson(holder.asJson())); + } +} diff --git a/nms/abstraction/pom.xml b/nms/abstraction/pom.xml index c13a0141..9c2de33e 100644 --- a/nms/abstraction/pom.xml +++ b/nms/abstraction/pom.xml @@ -5,7 +5,7 @@ IF-parent com.github.stefvanschie.inventoryframework - 0.10.5 + 0.10.6 ../../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index c747ace9..72476e5f 100644 --- a/pom.xml +++ b/pom.xml @@ -7,6 +7,7 @@ IF nms/abstraction + nms/1_19 nms/1_18_2 nms/1_18_1 nms/1_18_0 @@ -30,7 +31,7 @@ com.github.stefvanschie.inventoryframework IF-parent - 0.10.5 + 0.10.6 pom IF