UltimateModeration/src/main/java/com/songoda/ultimatemoderation/utils/gui/AbstractAnvilGUI.java

289 lines
11 KiB
Java

package com.songoda.ultimatemoderation.utils.gui;
import com.songoda.ultimatemoderation.UltimateModeration;
import com.songoda.ultimatemoderation.utils.version.NMSUtil;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import org.bukkit.inventory.meta.ItemMeta;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class AbstractAnvilGUI {
private static Class<?> BlockPositionClass;
private static Class<?> PacketPlayOutOpenWindowClass;
private static Class<?> IChatBaseComponentClass;
private static Class<?> ICraftingClass;
private static Class<?> ContainerAnvilClass;
private static Class<?> ChatMessageClass;
private static Class<?> EntityHumanClass;
private static Class<?> ContainerClass;
private static Class<?> ContainerAccessClass;
private static Class<?> WorldClass;
private static Class<?> PlayerInventoryClass;
private static Class<?> ContainersClass;
private static Class<?> CraftPlayerClass;
private Player player;
private Map<AnvilSlot, ItemStack> items = new HashMap<>();
private OnClose onClose = null;
private Inventory inv;
private Listener listener;
static {
BlockPositionClass = NMSUtil.getNMSClass("BlockPosition");
PacketPlayOutOpenWindowClass = NMSUtil.getNMSClass("PacketPlayOutOpenWindow");
IChatBaseComponentClass = NMSUtil.getNMSClass("IChatBaseComponent");
ICraftingClass = NMSUtil.getNMSClass("ICrafting");
ContainerAnvilClass = NMSUtil.getNMSClass("ContainerAnvil");
EntityHumanClass = NMSUtil.getNMSClass("EntityHuman");
ChatMessageClass = NMSUtil.getNMSClass("ChatMessage");
ContainerClass = NMSUtil.getNMSClass("Container");
WorldClass = NMSUtil.getNMSClass("World");
PlayerInventoryClass = NMSUtil.getNMSClass("PlayerInventory");
CraftPlayerClass = NMSUtil.getCraftClass("entity.CraftPlayer");
if (NMSUtil.getVersionNumber() > 13) {
ContainerAccessClass = NMSUtil.getNMSClass("ContainerAccess");
ContainersClass = NMSUtil.getNMSClass("Containers");
}
}
public AbstractAnvilGUI(Player player, AnvilClickEventHandler handler) {
UltimateModeration instance = UltimateModeration.getInstance();
this.player = player;
this.listener = new Listener() {
@EventHandler(priority = EventPriority.HIGHEST)
public void onInventoryClick(InventoryClickEvent event) {
if (event.getWhoClicked() instanceof Player && event.getInventory().equals(AbstractAnvilGUI.this.inv)) {
event.setCancelled(true);
ItemStack item = event.getCurrentItem();
int slot = event.getRawSlot();
if (item == null || item.getType().equals(Material.AIR) || slot != 2)
return;
String name = "";
ItemMeta meta = item.getItemMeta();
if (meta != null && meta.hasDisplayName())
name = meta.getDisplayName();
AnvilClickEvent clickEvent = new AnvilClickEvent(AnvilSlot.bySlot(slot), name);
handler.onAnvilClick(clickEvent);
if (clickEvent.getWillClose())
event.getWhoClicked().closeInventory();
if (clickEvent.getWillDestroy())
AbstractAnvilGUI.this.destroy();
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onInventoryClose(InventoryCloseEvent event) {
if (event.getPlayer() instanceof Player && AbstractAnvilGUI.this.inv.equals(event.getInventory())) {
Inventory inv = event.getInventory();
player.setLevel(player.getLevel() - 1);
inv.clear();
Bukkit.getScheduler().scheduleSyncDelayedTask(instance, () -> {
if (AbstractAnvilGUI.this.onClose != null)
AbstractAnvilGUI.this.onClose.onClose(player, inv);
AbstractAnvilGUI.this.destroy();
}, 1L);
}
}
@EventHandler(priority = EventPriority.HIGHEST)
public void onPlayerQuit(PlayerQuitEvent event) {
if (event.getPlayer().equals(AbstractAnvilGUI.this.player)) {
player.setLevel(player.getLevel() - 1);
AbstractAnvilGUI.this.destroy();
}
}
};
Bukkit.getPluginManager().registerEvents(this.listener, instance);
}
public Player getPlayer() {
return this.player;
}
public void setSlot(AnvilSlot slot, ItemStack item) {
this.items.put(slot, item);
}
public void open() {
this.player.setLevel(this.player.getLevel() + 1);
try {
Object craftPlayer = CraftPlayerClass.cast(this.player);
Method getHandleMethod = CraftPlayerClass.getMethod("getHandle");
Object entityPlayer = getHandleMethod.invoke(craftPlayer);
Object playerInventory = NMSUtil.getFieldObject(entityPlayer, NMSUtil.getField(entityPlayer.getClass(), "inventory", false));
Object world = NMSUtil.getFieldObject(entityPlayer, NMSUtil.getField(entityPlayer.getClass(), "world", false));
Object blockPosition = BlockPositionClass.getConstructor(int.class, int.class, int.class).newInstance(0, 0, 0);
Object container;
if (NMSUtil.getVersionNumber() > 13) {
container = ContainerAnvilClass
.getConstructor(int.class, PlayerInventoryClass, ContainerAccessClass)
.newInstance(7, playerInventory, ContainerAccessClass.getMethod("at", WorldClass, BlockPositionClass).invoke(null, world, blockPosition));
} else {
container = ContainerAnvilClass
.getConstructor(PlayerInventoryClass, WorldClass, BlockPositionClass, EntityHumanClass)
.newInstance(playerInventory, world, blockPosition, entityPlayer);
}
NMSUtil.getField(ContainerClass, "checkReachable", true).set(container, false);
Method getBukkitViewMethod = container.getClass().getMethod("getBukkitView");
Object bukkitView = getBukkitViewMethod.invoke(container);
Method getTopInventoryMethod = bukkitView.getClass().getMethod("getTopInventory");
this.inv = (Inventory) getTopInventoryMethod.invoke(bukkitView);
for (AnvilSlot slot : this.items.keySet()) {
this.inv.setItem(slot.getSlot(), this.items.get(slot));
}
Method nextContainerCounterMethod = entityPlayer.getClass().getMethod("nextContainerCounter");
int c = (int) nextContainerCounterMethod.invoke(entityPlayer);
Constructor<?> chatMessageConstructor = ChatMessageClass.getConstructor(String.class, Object[].class);
Object inventoryTitle = chatMessageConstructor.newInstance("Repairing", new Object[]{});
Object packet;
if (NMSUtil.getVersionNumber() > 13) {
packet = PacketPlayOutOpenWindowClass
.getConstructor(int.class, ContainersClass, IChatBaseComponentClass)
.newInstance(c, ContainersClass.getField("ANVIL").get(null), inventoryTitle);
} else {
packet = PacketPlayOutOpenWindowClass
.getConstructor(int.class, String.class, IChatBaseComponentClass, int.class)
.newInstance(c, "minecraft:anvil", inventoryTitle, 0);
}
NMSUtil.sendPacket(this.player, packet);
Field activeContainerField = NMSUtil.getField(EntityHumanClass, "activeContainer", true);
if (activeContainerField != null) {
activeContainerField.set(entityPlayer, container);
NMSUtil.getField(ContainerClass, "windowId", true).set(activeContainerField.get(entityPlayer), c);
Method addSlotListenerMethod = activeContainerField.get(entityPlayer).getClass().getMethod("addSlotListener", ICraftingClass);
addSlotListenerMethod.invoke(activeContainerField.get(entityPlayer), entityPlayer);
if (NMSUtil.getVersionNumber() > 13) {
ContainerClass.getMethod("setTitle", IChatBaseComponentClass).invoke(container, inventoryTitle);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
public void destroy() {
this.player = null;
this.items = null;
HandlerList.unregisterAll(this.listener);
this.listener = null;
}
private OnClose getOnClose() {
return this.onClose;
}
public void setOnClose(OnClose onClose) {
this.onClose = onClose;
}
public enum AnvilSlot {
INPUT_LEFT(0),
INPUT_RIGHT(1),
OUTPUT(2);
private int slot;
AnvilSlot(int slot) {
this.slot = slot;
}
public static AnvilSlot bySlot(int slot) {
for (AnvilSlot anvilSlot : values()) {
if (anvilSlot.getSlot() == slot) {
return anvilSlot;
}
}
return null;
}
public int getSlot() {
return this.slot;
}
}
@FunctionalInterface
public interface AnvilClickEventHandler {
void onAnvilClick(AnvilClickEvent event);
}
public class AnvilClickEvent {
private AnvilSlot slot;
private String name;
private boolean close = true;
private boolean destroy = true;
public AnvilClickEvent(AnvilSlot slot, String name) {
this.slot = slot;
this.name = name;
}
public AnvilSlot getSlot() {
return this.slot;
}
public String getName() {
return this.name;
}
public boolean getWillClose() {
return this.close;
}
public void setWillClose(boolean close) {
this.close = close;
}
public boolean getWillDestroy() {
return this.destroy;
}
public void setWillDestroy(boolean destroy) {
this.destroy = destroy;
}
}
}