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
-*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 extends Map.Entry extends MerchantRecipe, ? extends Integer>> trades,
+ int level, int experience) {
+ MerchantOffers offers = new MerchantOffers();
+
+ for (Map.Entry extends MerchantRecipe, ? extends Integer> 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