Merged with InventoryAccess

This commit is contained in:
NichtStudioCode 2021-06-12 15:15:31 +02:00
parent e1611d93fd
commit 61ddcc128e
99 changed files with 1852 additions and 114 deletions

6
.gitignore vendored

@ -55,6 +55,6 @@ target/
.libs/
# Testing
src/test/
src/main/java/de/studiocode/invui/InvUIPlugin.java
src/main/resources/plugin.yml
InvUI/src/test/
InvUI/src/main/java/de/studiocode/invui/InvUIPlugin.java
InvUI/src/main/resources/plugin.yml

131
InvUI/pom.xml Normal file

@ -0,0 +1,131 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>de.studiocode.invui</groupId>
<artifactId>InvUI-Parent</artifactId>
<version>0.1-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>InvUI</artifactId>
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>minecraft-repo</id>
<url>https://libraries.minecraft.net/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>16.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.17-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.mojang</groupId>
<artifactId>authlib</artifactId>
<version>1.5.21</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>de.studiocode.invui</groupId>
<artifactId>api</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>de.studiocode.invui</groupId>
<artifactId>1_14_R1</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>de.studiocode.invui</groupId>
<artifactId>1_15_R1</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>de.studiocode.invui</groupId>
<artifactId>1_16_R1</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>de.studiocode.invui</groupId>
<artifactId>1_16_R2</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>de.studiocode.invui</groupId>
<artifactId>1_16_R3</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>de.studiocode.invui</groupId>
<artifactId>1_17_R1</artifactId>
<version>0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>16</source>
<target>16</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<configuration>
<outputFile>${dir}/${project.artifactId}-${project.version}-shaded.jar</outputFile>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>*</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -12,12 +12,12 @@ import java.util.function.Supplier;
* An {@link Item} that updates it's {@link ItemBuilder} every specified amount
* of ticks.
*/
public class AutoUpdateItem extends SupplierItem {
public class AutoUpdateItem extends SuppliedItem {
private final BukkitTask task;
public AutoUpdateItem(int period, Supplier<ItemBuilder> builderSupplier) {
super(builderSupplier);
super(builderSupplier, null);
task = Bukkit.getScheduler().runTaskTimer(InvUI.getInstance().getPlugin(), this::notifyWindows, 0, period);
}

@ -32,13 +32,17 @@ public class CycleItem extends BaseItem {
@Override
public void handleClick(ClickType clickType, Player player, InventoryClickEvent event) {
if (clickType.isLeftClick()) {
if (++state == states.length) state = 0;
handleStateChange();
} else if (clickType.isRightClick()) {
if (--state < 0) state = states.length - 1;
handleStateChange();
if (clickType.isLeftClick()) cycle(true);
else if (clickType.isRightClick()) cycle(false);
}
public void cycle(boolean forward) {
if (forward) {
if (++state == states.length) state = 0;
} else {
if (--state < 0) state = states.length - 1;
}
handleStateChange();
}
private void handleStateChange() {

@ -7,6 +7,7 @@ import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Consumer;
@ -16,18 +17,16 @@ import java.util.function.Consumer;
public class SimpleItem extends BaseItem {
private final ItemBuilder itemBuilder;
private final Consumer<Click> clickHandler;
public SimpleItem(@NotNull ItemBuilder itemBuilder) {
this.itemBuilder = itemBuilder;
this.clickHandler = null;
}
public static SimpleItem of(ItemBuilder itemBuilder, Consumer<Click> clickHandler) {
return new SimpleItem(itemBuilder) {
@Override
public void handleClick(ClickType clickType, Player player, InventoryClickEvent event) {
clickHandler.accept(new Click(event));
}
};
public SimpleItem(@NotNull ItemBuilder itemBuilder, @Nullable Consumer<Click> clickHandler) {
this.itemBuilder = itemBuilder;
this.clickHandler = clickHandler;
}
public ItemBuilder getItemBuilder() {
@ -36,7 +35,7 @@ public class SimpleItem extends BaseItem {
@Override
public void handleClick(ClickType clickType, Player player, InventoryClickEvent event) {
// empty
if (clickHandler != null) clickHandler.accept(new Click(event));
}
}

@ -1,18 +1,24 @@
package de.studiocode.invui.item.impl;
import de.studiocode.invui.item.Click;
import de.studiocode.invui.item.ItemBuilder;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.function.Function;
import java.util.function.Supplier;
public class SupplierItem extends BaseItem {
public class SuppliedItem extends BaseItem {
private final Supplier<ItemBuilder> builderSupplier;
private final Function<Click, Boolean> clickHandler;
public SupplierItem(Supplier<ItemBuilder> builderSupplier) {
public SuppliedItem(@NotNull Supplier<ItemBuilder> builderSupplier, @Nullable Function<Click, Boolean> clickHandler) {
this.builderSupplier = builderSupplier;
this.clickHandler = clickHandler;
}
@Override
@ -22,7 +28,7 @@ public class SupplierItem extends BaseItem {
@Override
public void handleClick(ClickType clickType, Player player, InventoryClickEvent event) {
// empty
if (clickHandler != null && clickHandler.apply(new Click(event))) notifyWindows();
}
}

@ -1,23 +1,18 @@
package de.studiocode.invui.item.impl.controlitem;
import de.studiocode.invui.gui.GUI;
import de.studiocode.invui.item.impl.BaseItem;
import de.studiocode.invui.item.ItemBuilder;
import java.util.function.Function;
import de.studiocode.invui.item.impl.BaseItem;
public abstract class ControlItem<G extends GUI> extends BaseItem {
private G gui;
private final Function<G, ItemBuilder> builderFunction;
public ControlItem(Function<G, ItemBuilder> builderFunction) {
this.builderFunction = builderFunction;
}
public abstract ItemBuilder getItemBuilder(G gui);
@Override
public ItemBuilder getItemBuilder() {
return builderFunction.apply(gui);
public final ItemBuilder getItemBuilder() {
return getItemBuilder(gui);
}
public G getGui() {

@ -1,22 +1,18 @@
package de.studiocode.invui.item.impl.controlitem;
import de.studiocode.invui.gui.impl.PagedGUI;
import de.studiocode.invui.item.ItemBuilder;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.function.Function;
/**
* Switches between pages in a {@link PagedGUI}
*/
public class PageItem extends ControlItem<PagedGUI> {
public abstract class PageItem extends ControlItem<PagedGUI> {
private final boolean forward;
public PageItem(boolean forward, Function<PagedGUI, ItemBuilder> builderFunction) {
super(builderFunction);
public PageItem(boolean forward) {
this.forward = forward;
}

@ -1,29 +1,25 @@
package de.studiocode.invui.item.impl.controlitem;
import de.studiocode.invui.gui.impl.ScrollGUI;
import de.studiocode.invui.item.ItemBuilder;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.HashMap;
import java.util.function.Function;
/**
* Scrolls in a {@link ScrollGUI}
*/
public class ScrollItem extends ControlItem<ScrollGUI> {
public abstract class ScrollItem extends ControlItem<ScrollGUI> {
private final HashMap<ClickType, Integer> scroll;
public ScrollItem(int scrollLeftClick, Function<ScrollGUI, ItemBuilder> builderFunction) {
super(builderFunction);
public ScrollItem(int scrollLeftClick) {
scroll = new HashMap<>();
scroll.put(ClickType.LEFT, scrollLeftClick);
}
public ScrollItem(HashMap<ClickType, Integer> scroll, Function<ScrollGUI, ItemBuilder> builderFunction) {
super(builderFunction);
public ScrollItem(HashMap<ClickType, Integer> scroll) {
this.scroll = scroll;
}

@ -1,22 +1,18 @@
package de.studiocode.invui.item.impl.controlitem;
import de.studiocode.invui.gui.impl.TabGUI;
import de.studiocode.invui.item.ItemBuilder;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import java.util.function.Function;
/**
* Switches between tabs in a {@link TabGUI}
*/
public class TabItem extends ControlItem<TabGUI> {
public abstract class TabItem extends ControlItem<TabGUI> {
private final int tab;
public TabItem(int tab, Function<TabGUI, ItemBuilder> builderFunction) {
super(builderFunction);
public TabItem(int tab) {
this.tab = tab;
}

@ -42,7 +42,6 @@ public class ForceResourcePack implements Listener {
private ForceResourcePack() {
Bukkit.getPluginManager().registerEvents(this, InvUI.getInstance().getPlugin());
Bukkit.getOnlinePlayers().forEach(this::sendResourcePack);
}
public static ForceResourcePack getInstance() {
@ -51,12 +50,13 @@ public class ForceResourcePack implements Listener {
/**
* Sets the URL String for the custom ResourcePack every {@link Player} is required to download.
* Can be set to <code>null</code> to stop the forcing of a ResourcePack
* Can be set to null to stop forcing the Resource Pack.
*
* @param resourcePackUrl The ResourcePack URL String
*/
public void setResourcePackUrl(@Nullable String resourcePackUrl) {
this.resourcePackUrl = resourcePackUrl;
if (resourcePackUrl != null) Bukkit.getOnlinePlayers().forEach(this::sendResourcePack);
}
public String getResourcePackUrl() {

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>de.studiocode.invui</groupId>
<artifactId>InvUI-Parent</artifactId>
<version>0.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>1_14_R1</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.14.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>de.studiocode.invui</groupId>
<artifactId>api</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

@ -0,0 +1,172 @@
package de.studiocode.inventoryaccess.v1_14_R1.inventory;
import de.studiocode.inventoryaccess.api.abstraction.inventory.AnvilInventory;
import de.studiocode.inventoryaccess.api.version.ReflectionUtils;
import net.minecraft.server.v1_14_R1.*;
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_14_R1.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftInventoryAnvil;
import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftInventoryView;
import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.PrepareAnvilEvent;
import org.bukkit.inventory.Inventory;
import java.lang.reflect.Field;
import java.util.function.Consumer;
public class AnvilInventoryImpl extends ContainerAnvil implements AnvilInventory {
private static final Field CONTAINER_ACCESS_FIELD = ReflectionUtils.getField(ContainerAnvil.class, true, "containerAccess");
private static final Field REPAIR_INVENTORY_FIELD = ReflectionUtils.getField(ContainerAnvil.class, true, "repairInventory");
private static final Field RESULT_INVENTORY_FIELD = ReflectionUtils.getField(ContainerAnvil.class, true, "resultInventory");
private final String title;
private final Consumer<String> renameHandler;
private final CraftInventoryView view;
private final EntityPlayer player;
private final IInventory repairInventory;
private final IInventory resultInventory;
private String text;
private boolean open;
public AnvilInventoryImpl(Player player, String title, Consumer<String> renameHandler) {
this(((CraftPlayer) player).getHandle(), title, renameHandler);
}
public AnvilInventoryImpl(EntityPlayer player, String title, Consumer<String> renameHandler) {
super(player.nextContainerCounter(), player.inventory,
ContainerAccess.at(player.getWorld(), new BlockPosition(Integer.MAX_VALUE, 0, 0)));
this.title = title;
this.renameHandler = renameHandler;
this.player = player;
repairInventory = ReflectionUtils.getValueOfField(REPAIR_INVENTORY_FIELD, this);
resultInventory = ReflectionUtils.getValueOfField(RESULT_INVENTORY_FIELD, this);
ContainerAccess containerAccess = ReflectionUtils.getValueOfField(CONTAINER_ACCESS_FIELD, this);
CraftInventoryAnvil inventory = new CraftInventoryAnvil(containerAccess.getLocation(),
repairInventory, resultInventory, this);
this.view = new CraftInventoryView(player.getBukkitEntity(), inventory, this);
}
public void open() {
open = true;
// call the InventoryOpenEvent
CraftEventFactory.callInventoryOpenEvent(player, this);
// set active container
player.activeContainer = this;
// send open packet
player.playerConnection.sendPacket(new PacketPlayOutOpenWindow(windowId, Containers.ANVIL, new ChatMessage(title)));
// send initial items
NonNullList<ItemStack> itemsList = NonNullList.a(ItemStack.a, getItem(0), getItem(1), getItem(2));
player.playerConnection.sendPacket(new PacketPlayOutWindowItems(getActiveWindowId(player), itemsList));
}
public void sendItem(int slot) {
player.playerConnection.sendPacket(new PacketPlayOutSetSlot(getActiveWindowId(player), slot, getItem(slot)));
}
public void setItem(int slot, ItemStack item) {
if (slot < 2) repairInventory.setItem(slot, item);
else resultInventory.setItem(0, item);
if (open) sendItem(slot);
}
private ItemStack getItem(int slot) {
if (slot < 2) return repairInventory.getItem(slot);
else return resultInventory.getItem(0);
}
private int getActiveWindowId(EntityPlayer player) {
Container container = player.activeContainer;
return container == null ? -1 : container.windowId;
}
@Override
public void setItem(int slot, org.bukkit.inventory.ItemStack itemStack) {
setItem(slot, CraftItemStack.asNMSCopy(itemStack));
}
@Override
public Inventory getBukkitInventory() {
return view.getTopInventory();
}
@Override
public String getRenameText() {
return text;
}
@Override
public boolean isOpen() {
return open;
}
// --- ContainerAnvil ---
@Override
public CraftInventoryView getBukkitView() {
return view;
}
/**
* Called every tick to see if the {@link EntityHuman} can still use that container.
* (Used to for checking the distance between the {@link EntityHuman} and the container
* and closing the window when the distance gets too big.)
*
* @param entityhuman The {@link EntityHuman}
* @return If the {@link EntityHuman} can still use that container
*/
@Override
public boolean canUse(EntityHuman entityhuman) {
return true;
}
/**
* Called when the rename text gets changed.
*
* @param s The new rename text
*/
@Override
public void a(String s) {
// save rename text
text = s;
// call the rename handler
if (renameHandler != null) renameHandler.accept(s);
// the client expects the item to change to it's new name and removes it from the inventory, so it needs to be sent again
sendItem(2);
}
/**
* Called when the container is closed to give the items back.
*
* @param entityhuman The {@link EntityHuman} that closed this container
*/
@Override
public void b(EntityHuman entityhuman) {
open = false;
// don't give them the items, they don't own them
}
/**
* Called when both items in the {@link AnvilInventoryImpl#repairInventory} were set to create
* the resulting product, calculate the level cost and call the {@link PrepareAnvilEvent}.
*/
@Override
public void e() {
// no
}
}

@ -0,0 +1,27 @@
package de.studiocode.inventoryaccess.v1_14_R1.util;
import de.studiocode.inventoryaccess.api.abstraction.util.InventoryUtils;
import de.studiocode.inventoryaccess.api.version.ReflectionUtils;
import net.minecraft.server.v1_14_R1.Containers;
import net.minecraft.server.v1_14_R1.EntityPlayer;
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_14_R1.inventory.CraftContainer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import java.lang.reflect.Method;
public class InventoryUtilsImpl implements InventoryUtils {
private static final Method OPEN_CUSTOM_INVENTORY_METHOD = ReflectionUtils.getMethod(CraftHumanEntity.class,
true, "openCustomInventory", Inventory.class, EntityPlayer.class, Containers.class);
@Override
public void openCustomInventory(Player player, Inventory inventory) {
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
Containers<?> windowType = CraftContainer.getNotchInventoryType(inventory.getType());
ReflectionUtils.invokeMethod(OPEN_CUSTOM_INVENTORY_METHOD, player, inventory, entityPlayer, windowType);
}
}

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>de.studiocode.invui</groupId>
<artifactId>InvUI-Parent</artifactId>
<version>0.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>1_15_R1</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.15.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>de.studiocode.invui</groupId>
<artifactId>api</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

@ -0,0 +1,172 @@
package de.studiocode.inventoryaccess.v1_15_R1.inventory;
import de.studiocode.inventoryaccess.api.abstraction.inventory.AnvilInventory;
import de.studiocode.inventoryaccess.api.version.ReflectionUtils;
import net.minecraft.server.v1_15_R1.*;
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_15_R1.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftInventoryAnvil;
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftInventoryView;
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.PrepareAnvilEvent;
import org.bukkit.inventory.Inventory;
import java.lang.reflect.Field;
import java.util.function.Consumer;
public class AnvilInventoryImpl extends ContainerAnvil implements AnvilInventory {
private static final Field CONTAINER_ACCESS_FIELD = ReflectionUtils.getField(ContainerAnvil.class, true, "containerAccess");
private static final Field REPAIR_INVENTORY_FIELD = ReflectionUtils.getField(ContainerAnvil.class, true, "repairInventory");
private static final Field RESULT_INVENTORY_FIELD = ReflectionUtils.getField(ContainerAnvil.class, true, "resultInventory");
private final String title;
private final Consumer<String> renameHandler;
private final CraftInventoryView view;
private final EntityPlayer player;
private final IInventory repairInventory;
private final IInventory resultInventory;
private String text;
private boolean open;
public AnvilInventoryImpl(Player player, String title, Consumer<String> renameHandler) {
this(((CraftPlayer) player).getHandle(), title, renameHandler);
}
public AnvilInventoryImpl(EntityPlayer player, String title, Consumer<String> renameHandler) {
super(player.nextContainerCounter(), player.inventory,
ContainerAccess.at(player.getWorld(), new BlockPosition(Integer.MAX_VALUE, 0, 0)));
this.title = title;
this.renameHandler = renameHandler;
this.player = player;
repairInventory = ReflectionUtils.getValueOfField(REPAIR_INVENTORY_FIELD, this);
resultInventory = ReflectionUtils.getValueOfField(RESULT_INVENTORY_FIELD, this);
ContainerAccess containerAccess = ReflectionUtils.getValueOfField(CONTAINER_ACCESS_FIELD, this);
CraftInventoryAnvil inventory = new CraftInventoryAnvil(containerAccess.getLocation(),
repairInventory, resultInventory, this);
this.view = new CraftInventoryView(player.getBukkitEntity(), inventory, this);
}
public void open() {
open = true;
// call the InventoryOpenEvent
CraftEventFactory.callInventoryOpenEvent(player, this);
// set active container
player.activeContainer = this;
// send open packet
player.playerConnection.sendPacket(new PacketPlayOutOpenWindow(windowId, Containers.ANVIL, new ChatMessage(title)));
// send initial items
NonNullList<ItemStack> itemsList = NonNullList.a(ItemStack.a, getItem(0), getItem(1), getItem(2));
player.playerConnection.sendPacket(new PacketPlayOutWindowItems(getActiveWindowId(player), itemsList));
}
public void sendItem(int slot) {
player.playerConnection.sendPacket(new PacketPlayOutSetSlot(getActiveWindowId(player), slot, getItem(slot)));
}
public void setItem(int slot, ItemStack item) {
if (slot < 2) repairInventory.setItem(slot, item);
else resultInventory.setItem(0, item);
if (open) sendItem(slot);
}
private ItemStack getItem(int slot) {
if (slot < 2) return repairInventory.getItem(slot);
else return resultInventory.getItem(0);
}
private int getActiveWindowId(EntityPlayer player) {
Container container = player.activeContainer;
return container == null ? -1 : container.windowId;
}
@Override
public void setItem(int slot, org.bukkit.inventory.ItemStack itemStack) {
setItem(slot, CraftItemStack.asNMSCopy(itemStack));
}
@Override
public Inventory getBukkitInventory() {
return view.getTopInventory();
}
@Override
public String getRenameText() {
return text;
}
@Override
public boolean isOpen() {
return open;
}
// --- ContainerAnvil ---
@Override
public CraftInventoryView getBukkitView() {
return view;
}
/**
* Called every tick to see if the {@link EntityHuman} can still use that container.
* (Used to for checking the distance between the {@link EntityHuman} and the container
* and closing the window when the distance gets too big.)
*
* @param entityhuman The {@link EntityHuman}
* @return If the {@link EntityHuman} can still use that container
*/
@Override
public boolean canUse(EntityHuman entityhuman) {
return true;
}
/**
* Called when the rename text gets changed.
*
* @param s The new rename text
*/
@Override
public void a(String s) {
// save rename text
text = s;
// call the rename handler
if (renameHandler != null) renameHandler.accept(s);
// the client expects the item to change to it's new name and removes it from the inventory, so it needs to be sent again
sendItem(2);
}
/**
* Called when the container is closed to give the items back.
*
* @param entityhuman The {@link EntityHuman} that closed this container
*/
@Override
public void b(EntityHuman entityhuman) {
open = false;
// don't give them the items, they don't own them
}
/**
* Called when both items in the {@link de.studiocode.inventoryaccess.v1_14_R1.inventory.AnvilInventoryImpl#repairInventory} were set to create
* the resulting product, calculate the level cost and call the {@link PrepareAnvilEvent}.
*/
@Override
public void e() {
// no
}
}

@ -0,0 +1,27 @@
package de.studiocode.inventoryaccess.v1_15_R1.util;
import de.studiocode.inventoryaccess.api.abstraction.util.InventoryUtils;
import de.studiocode.inventoryaccess.api.version.ReflectionUtils;
import net.minecraft.server.v1_15_R1.Containers;
import net.minecraft.server.v1_15_R1.EntityPlayer;
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_15_R1.inventory.CraftContainer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import java.lang.reflect.Method;
public class InventoryUtilsImpl implements InventoryUtils {
private static final Method OPEN_CUSTOM_INVENTORY_METHOD = ReflectionUtils.getMethod(CraftHumanEntity.class,
true, "openCustomInventory", Inventory.class, EntityPlayer.class, Containers.class);
@Override
public void openCustomInventory(Player player, Inventory inventory) {
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
Containers<?> windowType = CraftContainer.getNotchInventoryType(inventory);
ReflectionUtils.invokeMethod(OPEN_CUSTOM_INVENTORY_METHOD, player, inventory, entityPlayer, windowType);
}
}

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>de.studiocode.invui</groupId>
<artifactId>InvUI-Parent</artifactId>
<version>0.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>1_16_R1</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.16.1-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>de.studiocode.invui</groupId>
<artifactId>api</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

@ -0,0 +1,158 @@
package de.studiocode.inventoryaccess.v1_16_R1.inventory;
import de.studiocode.inventoryaccess.api.abstraction.inventory.AnvilInventory;
import net.minecraft.server.v1_16_R1.*;
import org.bukkit.craftbukkit.v1_16_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_16_R1.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_16_R1.inventory.CraftInventoryAnvil;
import org.bukkit.craftbukkit.v1_16_R1.inventory.CraftInventoryView;
import org.bukkit.craftbukkit.v1_16_R1.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import java.util.function.Consumer;
public class AnvilInventoryImpl extends ContainerAnvil implements AnvilInventory {
private final String title;
private final Consumer<String> renameHandler;
private final CraftInventoryView view;
private final EntityPlayer player;
private String text;
private boolean open;
public AnvilInventoryImpl(Player player, String title, Consumer<String> renameHandler) {
this(((CraftPlayer) player).getHandle(), title, renameHandler);
}
public AnvilInventoryImpl(EntityPlayer player, String title, Consumer<String> renameHandler) {
super(player.nextContainerCounter(), player.inventory,
ContainerAccess.at(player.getWorld(), new BlockPosition(Integer.MAX_VALUE, 0, 0)));
this.title = title;
this.renameHandler = renameHandler;
this.player = player;
CraftInventoryAnvil inventory = new CraftInventoryAnvil(containerAccess.getLocation(),
repairInventory, resultInventory, this);
this.view = new CraftInventoryView(player.getBukkitEntity(), inventory, this);
}
public void open() {
open = true;
// call the InventoryOpenEvent
CraftEventFactory.callInventoryOpenEvent(player, this);
// set active container
player.activeContainer = this;
// send open packet
player.playerConnection.sendPacket(new PacketPlayOutOpenWindow(windowId, Containers.ANVIL, new ChatMessage(title)));
// send initial items
NonNullList<ItemStack> itemsList = NonNullList.a(ItemStack.b, getItem(0), getItem(1), getItem(2));
player.playerConnection.sendPacket(new PacketPlayOutWindowItems(getActiveWindowId(player), itemsList));
}
public void sendItem(int slot) {
player.playerConnection.sendPacket(new PacketPlayOutSetSlot(getActiveWindowId(player), slot, getItem(slot)));
}
public void setItem(int slot, ItemStack item) {
if (slot < 2) repairInventory.setItem(slot, item);
else resultInventory.setItem(0, item);
if (open) sendItem(slot);
}
private ItemStack getItem(int slot) {
if (slot < 2) return repairInventory.getItem(slot);
else return resultInventory.getItem(0);
}
private int getActiveWindowId(EntityPlayer player) {
Container container = player.activeContainer;
return container == null ? -1 : container.windowId;
}
@Override
public void setItem(int slot, org.bukkit.inventory.ItemStack itemStack) {
setItem(slot, CraftItemStack.asNMSCopy(itemStack));
}
@Override
public Inventory getBukkitInventory() {
return view.getTopInventory();
}
@Override
public String getRenameText() {
return text;
}
@Override
public boolean isOpen() {
return open;
}
// --- ContainerAnvil ---
@Override
public CraftInventoryView getBukkitView() {
return view;
}
/**
* Called every tick to see if the {@link EntityHuman} can still use that container.
* (Used to for checking the distance between the {@link EntityHuman} and the container
* and closing the window when the distance gets too big.)
*
* @param entityhuman The {@link EntityHuman}
* @return If the {@link EntityHuman} can still use that container
*/
@Override
public boolean canUse(EntityHuman entityhuman) {
return true;
}
/**
* Called when the rename text gets changed.
*
* @param s The new rename text
*/
@Override
public void a(String s) {
// save rename text
text = s;
// call the rename handler
if (renameHandler != null) renameHandler.accept(s);
// the client expects the item to change to it's new name and removes it from the inventory, so it needs to be sent again
sendItem(2);
}
/**
* Called when the container is closed to give the items back.
*
* @param entityhuman The {@link EntityHuman} that closed this container
*/
@Override
public void b(EntityHuman entityhuman) {
open = false;
// don't give them the items, they don't own them
}
/**
* Called when both items in the {@link ContainerAnvil#repairInventory} were set to create
* the resulting product, calculate the level cost and call the {@link PrepareAnvilEvent}.
*/
@Override
public void e() {
// no
}
}

@ -0,0 +1,27 @@
package de.studiocode.inventoryaccess.v1_16_R1.util;
import de.studiocode.inventoryaccess.api.abstraction.util.InventoryUtils;
import de.studiocode.inventoryaccess.api.version.ReflectionUtils;
import net.minecraft.server.v1_16_R1.Containers;
import net.minecraft.server.v1_16_R1.EntityPlayer;
import org.bukkit.craftbukkit.v1_16_R1.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v1_16_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_16_R1.inventory.CraftContainer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import java.lang.reflect.Method;
public class InventoryUtilsImpl implements InventoryUtils {
private static final Method OPEN_CUSTOM_INVENTORY_METHOD = ReflectionUtils.getMethod(CraftHumanEntity.class,
true, "openCustomInventory", Inventory.class, EntityPlayer.class, Containers.class);
@Override
public void openCustomInventory(Player player, Inventory inventory) {
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
Containers<?> windowType = CraftContainer.getNotchInventoryType(inventory);
ReflectionUtils.invokeMethod(OPEN_CUSTOM_INVENTORY_METHOD, player, inventory, entityPlayer, windowType);
}
}

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>de.studiocode.invui</groupId>
<artifactId>InvUI-Parent</artifactId>
<version>0.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>1_16_R2</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.16.2-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>de.studiocode.invui</groupId>
<artifactId>api</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

@ -0,0 +1,159 @@
package de.studiocode.inventoryaccess.v1_16_R2.inventory;
import de.studiocode.inventoryaccess.api.abstraction.inventory.AnvilInventory;
import net.minecraft.server.v1_16_R2.*;
import org.bukkit.craftbukkit.v1_16_R2.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_16_R2.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftInventoryAnvil;
import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftInventoryView;
import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.PrepareAnvilEvent;
import org.bukkit.inventory.Inventory;
import java.util.function.Consumer;
public class AnvilInventoryImpl extends ContainerAnvil implements AnvilInventory {
private final String title;
private final Consumer<String> renameHandler;
private final CraftInventoryView view;
private final EntityPlayer player;
private String text;
private boolean open;
public AnvilInventoryImpl(Player player, String title, Consumer<String> renameHandler) {
this(((CraftPlayer) player).getHandle(), title, renameHandler);
}
public AnvilInventoryImpl(EntityPlayer player, String title, Consumer<String> renameHandler) {
super(player.nextContainerCounter(), player.inventory,
ContainerAccess.at(player.getWorld(), new BlockPosition(Integer.MAX_VALUE, 0, 0)));
this.title = title;
this.renameHandler = renameHandler;
this.player = player;
CraftInventoryAnvil inventory = new CraftInventoryAnvil(containerAccess.getLocation(),
repairInventory, resultInventory, this);
this.view = new CraftInventoryView(player.getBukkitEntity(), inventory, this);
}
public void open() {
open = true;
// call the InventoryOpenEvent
CraftEventFactory.callInventoryOpenEvent(player, this);
// set active container
player.activeContainer = this;
// send open packet
player.playerConnection.sendPacket(new PacketPlayOutOpenWindow(windowId, Containers.ANVIL, new ChatMessage(title)));
// send initial items
NonNullList<ItemStack> itemsList = NonNullList.a(ItemStack.b, getItem(0), getItem(1), getItem(2));
player.playerConnection.sendPacket(new PacketPlayOutWindowItems(getActiveWindowId(player), itemsList));
}
public void sendItem(int slot) {
player.playerConnection.sendPacket(new PacketPlayOutSetSlot(getActiveWindowId(player), slot, getItem(slot)));
}
public void setItem(int slot, ItemStack item) {
if (slot < 2) repairInventory.setItem(slot, item);
else resultInventory.setItem(0, item);
if (open) sendItem(slot);
}
private ItemStack getItem(int slot) {
if (slot < 2) return repairInventory.getItem(slot);
else return resultInventory.getItem(0);
}
private int getActiveWindowId(EntityPlayer player) {
Container container = player.activeContainer;
return container == null ? -1 : container.windowId;
}
@Override
public void setItem(int slot, org.bukkit.inventory.ItemStack itemStack) {
setItem(slot, CraftItemStack.asNMSCopy(itemStack));
}
@Override
public Inventory getBukkitInventory() {
return view.getTopInventory();
}
@Override
public String getRenameText() {
return text;
}
@Override
public boolean isOpen() {
return open;
}
// --- ContainerAnvil ---
@Override
public CraftInventoryView getBukkitView() {
return view;
}
/**
* Called every tick to see if the {@link EntityHuman} can still use that container.
* (Used to for checking the distance between the {@link EntityHuman} and the container
* and closing the window when the distance gets too big.)
*
* @param entityhuman The {@link EntityHuman}
* @return If the {@link EntityHuman} can still use that container
*/
@Override
public boolean canUse(EntityHuman entityhuman) {
return true;
}
/**
* Called when the rename text gets changed.
*
* @param s The new rename text
*/
@Override
public void a(String s) {
// save rename text
text = s;
// call the rename handler
if (renameHandler != null) renameHandler.accept(s);
// the client expects the item to change to it's new name and removes it from the inventory, so it needs to be sent again
sendItem(2);
}
/**
* Called when the container is closed to give the items back.
*
* @param entityhuman The {@link EntityHuman} that closed this container
*/
@Override
public void b(EntityHuman entityhuman) {
open = false;
// don't give them the items, they don't own them
}
/**
* Called when both items in the {@link ContainerAnvil#repairInventory} were set to create
* the resulting product, calculate the level cost and call the {@link PrepareAnvilEvent}.
*/
@Override
public void e() {
// no
}
}

@ -0,0 +1,27 @@
package de.studiocode.inventoryaccess.v1_16_R2.util;
import de.studiocode.inventoryaccess.api.abstraction.util.InventoryUtils;
import de.studiocode.inventoryaccess.api.version.ReflectionUtils;
import net.minecraft.server.v1_16_R2.Containers;
import net.minecraft.server.v1_16_R2.EntityPlayer;
import org.bukkit.craftbukkit.v1_16_R2.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v1_16_R2.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_16_R2.inventory.CraftContainer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import java.lang.reflect.Method;
public class InventoryUtilsImpl implements InventoryUtils {
private static final Method OPEN_CUSTOM_INVENTORY_METHOD = ReflectionUtils.getMethod(CraftHumanEntity.class,
true, "openCustomInventory", Inventory.class, EntityPlayer.class, Containers.class);
@Override
public void openCustomInventory(Player player, Inventory inventory) {
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
Containers<?> windowType = CraftContainer.getNotchInventoryType(inventory);
ReflectionUtils.invokeMethod(OPEN_CUSTOM_INVENTORY_METHOD, player, inventory, entityPlayer, windowType);
}
}

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>de.studiocode.invui</groupId>
<artifactId>InvUI-Parent</artifactId>
<version>0.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>1_16_R3</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.16.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>de.studiocode.invui</groupId>
<artifactId>api</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
</project>

@ -0,0 +1,159 @@
package de.studiocode.inventoryaccess.v1_16_R3.inventory;
import de.studiocode.inventoryaccess.api.abstraction.inventory.AnvilInventory;
import net.minecraft.server.v1_16_R3.*;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_16_R3.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftInventoryAnvil;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftInventoryView;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftItemStack;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.PrepareAnvilEvent;
import org.bukkit.inventory.Inventory;
import java.util.function.Consumer;
public class AnvilInventoryImpl extends ContainerAnvil implements AnvilInventory {
private final String title;
private final Consumer<String> renameHandler;
private final CraftInventoryView view;
private final EntityPlayer player;
private String text;
private boolean open;
public AnvilInventoryImpl(Player player, String title, Consumer<String> renameHandler) {
this(((CraftPlayer) player).getHandle(), title, renameHandler);
}
public AnvilInventoryImpl(EntityPlayer player, String title, Consumer<String> renameHandler) {
super(player.nextContainerCounter(), player.inventory,
ContainerAccess.at(player.getWorld(), new BlockPosition(Integer.MAX_VALUE, 0, 0)));
this.title = title;
this.renameHandler = renameHandler;
this.player = player;
CraftInventoryAnvil inventory = new CraftInventoryAnvil(containerAccess.getLocation(),
repairInventory, resultInventory, this);
this.view = new CraftInventoryView(player.getBukkitEntity(), inventory, this);
}
public void open() {
open = true;
// call the InventoryOpenEvent
CraftEventFactory.callInventoryOpenEvent(player, this);
// set active container
player.activeContainer = this;
// send open packet
player.playerConnection.sendPacket(new PacketPlayOutOpenWindow(windowId, Containers.ANVIL, new ChatMessage(title)));
// send initial items
NonNullList<ItemStack> itemsList = NonNullList.a(ItemStack.b, getItem(0), getItem(1), getItem(2));
player.playerConnection.sendPacket(new PacketPlayOutWindowItems(getActiveWindowId(player), itemsList));
}
public void sendItem(int slot) {
player.playerConnection.sendPacket(new PacketPlayOutSetSlot(getActiveWindowId(player), slot, getItem(slot)));
}
public void setItem(int slot, ItemStack item) {
if (slot < 2) repairInventory.setItem(slot, item);
else resultInventory.setItem(0, item);
if (open) sendItem(slot);
}
private ItemStack getItem(int slot) {
if (slot < 2) return repairInventory.getItem(slot);
else return resultInventory.getItem(0);
}
private int getActiveWindowId(EntityPlayer player) {
Container container = player.activeContainer;
return container == null ? -1 : container.windowId;
}
@Override
public void setItem(int slot, org.bukkit.inventory.ItemStack itemStack) {
setItem(slot, CraftItemStack.asNMSCopy(itemStack));
}
@Override
public Inventory getBukkitInventory() {
return view.getTopInventory();
}
@Override
public String getRenameText() {
return text;
}
@Override
public boolean isOpen() {
return open;
}
// --- ContainerAnvil ---
@Override
public CraftInventoryView getBukkitView() {
return view;
}
/**
* Called every tick to see if the {@link EntityHuman} can still use that container.
* (Used to for checking the distance between the {@link EntityHuman} and the container
* and closing the window when the distance gets too big.)
*
* @param entityhuman The {@link EntityHuman}
* @return If the {@link EntityHuman} can still use that container
*/
@Override
public boolean canUse(EntityHuman entityhuman) {
return true;
}
/**
* Called when the rename text gets changed.
*
* @param s The new rename text
*/
@Override
public void a(String s) {
// save rename text
text = s;
// call the rename handler
if (renameHandler != null) renameHandler.accept(s);
// the client expects the item to change to it's new name and removes it from the inventory, so it needs to be sent again
sendItem(2);
}
/**
* Called when the container is closed to give the items back.
*
* @param entityhuman The {@link EntityHuman} that closed this container
*/
@Override
public void b(EntityHuman entityhuman) {
open = false;
// don't give them the items, they don't own them
}
/**
* Called when both items in the {@link ContainerAnvil#repairInventory} were set to create
* the resulting product, calculate the level cost and call the {@link PrepareAnvilEvent}.
*/
@Override
public void e() {
// no
}
}

@ -0,0 +1,27 @@
package de.studiocode.inventoryaccess.v1_16_R3.util;
import de.studiocode.inventoryaccess.api.abstraction.util.InventoryUtils;
import de.studiocode.inventoryaccess.api.version.ReflectionUtils;
import net.minecraft.server.v1_16_R3.Containers;
import net.minecraft.server.v1_16_R3.EntityPlayer;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_16_R3.inventory.CraftContainer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import java.lang.reflect.Method;
public class InventoryUtilsImpl implements InventoryUtils {
private static final Method OPEN_CUSTOM_INVENTORY_METHOD = ReflectionUtils.getMethod(CraftHumanEntity.class,
true, "openCustomInventory", Inventory.class, EntityPlayer.class, Containers.class);
@Override
public void openCustomInventory(Player player, Inventory inventory) {
EntityPlayer entityPlayer = ((CraftPlayer) player).getHandle();
Containers<?> windowType = CraftContainer.getNotchInventoryType(inventory);
ReflectionUtils.invokeMethod(OPEN_CUSTOM_INVENTORY_METHOD, player, inventory, entityPlayer, windowType);
}
}

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>de.studiocode.invui</groupId>
<artifactId>InvUI-Parent</artifactId>
<version>0.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>1_17_R1</artifactId>
<properties>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot</artifactId>
<version>1.17-R0.1-SNAPSHOT</version>
<classifier>remapped-mojang</classifier>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>de.studiocode.invui</groupId>
<artifactId>api</artifactId>
<version>${project.parent.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>net.md-5</groupId>
<artifactId>specialsource-maven-plugin</artifactId>
<version>1.2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>remap</goal>
</goals>
<id>remap-obf</id>
<configuration>
<srgIn>org.spigotmc:minecraft-server:1.17-R0.1-SNAPSHOT:txt:maps-mojang</srgIn>
<reverse>true</reverse>
<remappedDependencies>org.spigotmc:spigot:1.17-R0.1-SNAPSHOT:jar:remapped-mojang</remappedDependencies>
<remappedArtifactAttached>true</remappedArtifactAttached>
<remappedClassifierName>remapped-obf</remappedClassifierName>
</configuration>
</execution>
<execution>
<phase>package</phase>
<goals>
<goal>remap</goal>
</goals>
<id>remap-spigot</id>
<configuration>
<inputFile>${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar</inputFile>
<srgIn>org.spigotmc:minecraft-server:1.17-R0.1-SNAPSHOT:csrg:maps-spigot</srgIn>
<remappedDependencies>org.spigotmc:spigot:1.17-R0.1-SNAPSHOT:jar:remapped-obf</remappedDependencies>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

@ -0,0 +1,186 @@
package de.studiocode.inventoryaccess.v1_17_R1.inventory;
import de.studiocode.inventoryaccess.api.abstraction.inventory.AnvilInventory;
import net.minecraft.core.BlockPos;
import net.minecraft.core.NonNullList;
import net.minecraft.network.chat.TextComponent;
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.world.Container;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
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.craftbukkit.v1_17_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_17_R1.event.CraftEventFactory;
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftInventoryAnvil;
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftInventoryView;
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftItemStack;
import org.bukkit.event.inventory.PrepareAnvilEvent;
import org.bukkit.inventory.Inventory;
import java.util.function.Consumer;
public class AnvilInventoryImpl extends AnvilMenu implements AnvilInventory {
private final String title;
private final Consumer<String> renameHandler;
private final CraftInventoryView view;
private final ServerPlayer player;
private String text;
private boolean open;
public AnvilInventoryImpl(org.bukkit.entity.Player player, String title, Consumer<String> renameHandler) {
this(((CraftPlayer) player).getHandle(), title, renameHandler);
}
public AnvilInventoryImpl(ServerPlayer player, String title, Consumer<String> renameHandler) {
super(player.nextContainerCounter(), player.getInventory(),
ContainerLevelAccess.create(player.level, new BlockPos(Integer.MAX_VALUE, 0, 0)));
this.title = title;
this.renameHandler = renameHandler;
this.player = player;
CraftInventoryAnvil inventory = new CraftInventoryAnvil(access.getLocation(),
inputSlots, resultSlots, this);
this.view = new CraftInventoryView(player.getBukkitEntity(), inventory, this);
}
public void open() {
open = true;
// call the InventoryOpenEvent
CraftEventFactory.callInventoryOpenEvent(player, this);
// set active container
player.containerMenu = this;
// send open packet
player.connection.send(new ClientboundOpenScreenPacket(containerId, MenuType.ANVIL, new TextComponent(title)));
// send initial items
NonNullList<ItemStack> itemsList = NonNullList.of(ItemStack.EMPTY, getItem(0), getItem(1), getItem(2));
player.connection.send(new ClientboundContainerSetContentPacket(getActiveWindowId(player), itemsList));
// init menu
player.initMenu(this);
}
public void sendItem(int slot) {
player.connection.send(new ClientboundContainerSetSlotPacket(getActiveWindowId(player), slot, getItem(slot)));
}
public void setItem(int slot, ItemStack item) {
if (slot < 2) inputSlots.setItem(slot, item);
else resultSlots.setItem(0, item);
if (open) sendItem(slot);
}
private ItemStack getItem(int slot) {
if (slot < 2) return inputSlots.getItem(slot);
else return resultSlots.getItem(0);
}
private int getActiveWindowId(ServerPlayer player) {
AbstractContainerMenu container = player.containerMenu;
return container == null ? -1 : container.containerId;
}
@Override
public void setItem(int slot, org.bukkit.inventory.ItemStack itemStack) {
setItem(slot, CraftItemStack.asNMSCopy(itemStack));
}
@Override
public Inventory getBukkitInventory() {
return view.getTopInventory();
}
@Override
public String getRenameText() {
return text;
}
@Override
public boolean isOpen() {
return open;
}
// --- ContainerAnvil ---
@Override
public CraftInventoryView getBukkitView() {
return view;
}
/**
* Called every tick to see if the {@link Player} can still use that container.
* (Used to for checking the distance between the {@link Player} and the container
* and closing the window when the distance gets too big.)
*
* @param player The {@link Player}
* @return If the {@link Player} can still use that container
*/
@Override
public boolean stillValid(Player player) {
return true;
}
/**
* Called when the rename text gets changed.
*
* @param s The new rename text
*/
@Override
public void setItemName(String s) {
// save rename text
text = s;
// call the rename handler
if (renameHandler != null) renameHandler.accept(s);
// the client expects the item to change to it's new name and removes it from the inventory, so it needs to be sent again
sendItem(2);
}
/**
* Called when the container is closed to give the items back.
*
* @param player The {@link Player} that closed this container
*/
@Override
public void removed(Player player) {
open = false;
}
/**
* Called when the container gets closed to put items back into a players
* inventory or drop them in the world.
*
* @param player The {@link Player} that closed this container
* @param container The container
*/
@Override
protected void clearContainer(Player player, Container container) {
open = false;
}
/**
* Called when both items in the {@link AnvilMenu#inputSlots} were set to create
* the resulting product, calculate the level cost and call the {@link PrepareAnvilEvent}.
*/
@Override
public void createResult() {
// empty
}
}

@ -0,0 +1,28 @@
package de.studiocode.inventoryaccess.v1_17_R1.util;
import de.studiocode.inventoryaccess.api.abstraction.util.InventoryUtils;
import de.studiocode.inventoryaccess.api.version.ReflectionUtils;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.inventory.MenuType;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftHumanEntity;
import org.bukkit.craftbukkit.v1_17_R1.entity.CraftPlayer;
import org.bukkit.craftbukkit.v1_17_R1.inventory.CraftContainer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import java.lang.reflect.Method;
public class InventoryUtilsImpl implements InventoryUtils {
private static final Method OPEN_CUSTOM_INVENTORY_METHOD = ReflectionUtils.getMethod(CraftHumanEntity.class,
true, "openCustomInventory", Inventory.class, ServerPlayer.class, MenuType.class);
@Override
public void openCustomInventory(Player player, Inventory inventory) {
ServerPlayer serverPlayer = ((CraftPlayer) player).getHandle();
MenuType<?> menuType = CraftContainer.getNotchInventoryType(inventory);
ReflectionUtils.invokeMethod(OPEN_CUSTOM_INVENTORY_METHOD, null, inventory, serverPlayer, menuType);
serverPlayer.containerMenu.checkReachable = false;
}
}

@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>de.studiocode.invui</groupId>
<artifactId>InvUI-Parent</artifactId>
<version>0.1-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>api</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.16.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

@ -0,0 +1,42 @@
package de.studiocode.inventoryaccess.api.abstraction.inventory;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public interface AnvilInventory {
/**
* Gets Bukkit's {@link Inventory} associated to this {@link AnvilInventory}
*
* @return The {@link Inventory}
*/
Inventory getBukkitInventory();
/**
* Opens the inventory.
*/
void open();
/**
* Sets an {@link ItemStack} on one of the three slots.
*
* @param slot The slot
* @param itemStack The {@link ItemStack}
*/
void setItem(int slot, ItemStack itemStack);
/**
* Gets the rename text the user has typed in the renaming section of the anvil.
*
* @return The rename text
*/
String getRenameText();
/**
* Gets if this inventory is currently open.
*
* @return If the inventory is currently open
*/
boolean isOpen();
}

@ -0,0 +1,20 @@
package de.studiocode.inventoryaccess.api.abstraction.util;
import org.bukkit.entity.Player;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryView;
public interface InventoryUtils {
/**
* Opens an {@link Inventory} as a custom inventory.
* Internally, this creates a CraftContainer which can save the {@link InventoryView},
* unlike when using nms Containers, which is the default way for opening Inventories of
* TileEntities.
*
* @param player The {@link Player} to open the {@link Inventory} for
* @param inventory The {@link Inventory}
*/
void openCustomInventory(Player player, Inventory inventory);
}

@ -0,0 +1,42 @@
package de.studiocode.inventoryaccess.api.version;
import de.studiocode.inventoryaccess.api.abstraction.inventory.AnvilInventory;
import de.studiocode.inventoryaccess.api.abstraction.util.InventoryUtils;
import org.bukkit.entity.Player;
import java.lang.reflect.Constructor;
import java.util.function.Consumer;
public class InventoryAccess {
private static final Class<InventoryUtils> INVENTORY_UTILS_CLASS = ReflectionUtils.getClass("util.InventoryUtilsImpl");
private static final Class<AnvilInventory> ANVIL_INVENTORY_CLASS = ReflectionUtils.getClass("inventory.AnvilInventoryImpl");
private static final Constructor<AnvilInventory> ANVIL_INVENTORY_CONSTRUCTOR
= ReflectionUtils.getConstructor(ANVIL_INVENTORY_CLASS, Player.class, String.class, Consumer.class);
private static final InventoryUtils INVENTORY_UTILS = ReflectionUtils.constructEmpty(INVENTORY_UTILS_CLASS);
/**
* Gets the {@link InventoryUtils}
*
* @return The {@link InventoryUtils}
*/
public static InventoryUtils getInventoryUtils() {
return INVENTORY_UTILS;
}
/**
* Creates a new {@link AnvilInventory}.
*
* @param player The {@link Player} that should see this {@link AnvilInventory}
* @param title The title {@link String} of the {@link AnvilInventory}
* @param renameHandler A {@link Consumer} that is called whenever the {@link Player}
* types something in the renaming section of the anvil
* @return The {@link AnvilInventory}
*/
public static AnvilInventory createAnvilInventory(Player player, String title, Consumer<String> renameHandler) {
return ReflectionUtils.construct(ANVIL_INVENTORY_CONSTRUCTOR, player, title, renameHandler);
}
}

@ -0,0 +1,105 @@
package de.studiocode.inventoryaccess.api.version;
import org.bukkit.Bukkit;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectionUtils {
private static final String VERSION = getVersion();
private static String getVersion() {
String path = Bukkit.getServer().getClass().getPackage().getName();
return path.substring(path.lastIndexOf(".") + 1);
}
@SuppressWarnings("unchecked")
public static <T> Class<T> getClass(String path) {
try {
return (Class<T>) Class.forName("de.studiocode.inventoryaccess." + VERSION + "." + path);
} catch (ClassNotFoundException e) {
throw new UnsupportedOperationException("Your version (" + VERSION + ") is not supported by InventoryAccess");
}
}
public static <T> Constructor<T> getConstructor(Class<T> clazz, Class<?>... parameterTypes) {
try {
return clazz.getConstructor(parameterTypes);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
@SuppressWarnings("unchecked")
public static <T> T constructEmpty(Class<?> clazz) {
try {
return (T) clazz.getConstructor().newInstance();
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
return null;
}
public static <T> T construct(Constructor<T> constructor, Object... args) {
try {
return constructor.newInstance(args);
} catch (ReflectiveOperationException e) {
e.printStackTrace();
}
return null;
}
public static Field getField(Class<?> clazz, boolean declared, String name) {
try {
Field field = declared ? clazz.getDeclaredField(name) : clazz.getField(name);
if (declared) field.setAccessible(true);
return field;
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return null;
}
@SuppressWarnings("unchecked")
public static <T> T getValueOfField(Field field, Object obj) {
try {
return (T) field.get(obj);
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public static Method getMethod(Class<?> clazz, boolean declared, String name, Class<?>... parameterTypes) {
try {
Method method = declared ? clazz.getDeclaredMethod(name, parameterTypes) : clazz.getMethod(name, parameterTypes);
if (declared) method.setAccessible(true);
return method;
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
@SuppressWarnings("unchecked")
public static <T> T invokeMethod(Method method, Object obj, Object... args) {
try {
return (T) method.invoke(obj, args);
} catch (IllegalAccessException | InvocationTargetException e) {
e.printStackTrace();
}
return null;
}
}

75
pom.xml

@ -4,69 +4,20 @@
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>de.studiocode</groupId>
<artifactId>InvUI</artifactId>
<groupId>de.studiocode.invui</groupId>
<artifactId>InvUI-Parent</artifactId>
<version>0.1-SNAPSHOT</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>8</source>
<target>8</target>
</configuration>
</plugin>
</plugins>
</build>
<packaging>pom</packaging>
<repositories>
<repository>
<id>spigot-repo</id>
<url>https://hub.spigotmc.org/nexus/content/repositories/snapshots/</url>
</repository>
<repository>
<id>minecraft-repo</id>
<url>https://libraries.minecraft.net/</url>
</repository>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.jetbrains</groupId>
<artifactId>annotations</artifactId>
<version>16.0.1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.16.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>com.mojang</groupId>
<artifactId>authlib</artifactId>
<version>1.5.21</version>
<scope>provided</scope>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.github.NichtStudioCode</groupId>
<artifactId>InventoryAccess</artifactId>
<version>0.3</version>
<scope>compile</scope>
</dependency>
</dependencies>
<modules>
<module>InventoryAccess/1_14_R1</module>
<module>InventoryAccess/1_15_R1</module>
<module>InventoryAccess/1_16_R1</module>
<module>InventoryAccess/1_16_R2</module>
<module>InventoryAccess/1_16_R3</module>
<module>InventoryAccess/1_17_R1</module>
<module>InventoryAccess/api</module>
<module>InvUI</module>
</modules>
</project>