Fix for anvil GUI's

This commit is contained in:
Brianna 2019-04-24 02:51:40 -04:00
parent 5e40f09a04
commit 6b38468175

View File

@ -1,12 +1,12 @@
package com.songoda.ultimatemoderation.utils.gui; package com.songoda.ultimatemoderation.utils.gui;
import com.songoda.ultimatemoderation.UltimateModeration; import com.songoda.ultimatemoderation.UltimateModeration;
import com.songoda.ultimatemoderation.utils.ServerVersion;
import com.songoda.ultimatemoderation.utils.version.NMSUtil; import com.songoda.ultimatemoderation.utils.version.NMSUtil;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.Sound; import org.bukkit.Sound;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.HandlerList; import org.bukkit.event.HandlerList;
import org.bukkit.event.Listener; import org.bukkit.event.Listener;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
@ -24,97 +24,114 @@ import java.util.Map;
public class AbstractAnvilGUI { public class AbstractAnvilGUI {
private static Class<?> BlockPosition; private static Class<?> BlockPositionClass;
private static Class<?> PacketPlayOutOpenWindow; private static Class<?> PacketPlayOutOpenWindowClass;
private static Class<?> ContainerAnvil; private static Class<?> IChatBaseComponentClass;
private static Class<?> ChatMessage; private static Class<?> ICraftingClass;
private static Class<?> EntityHuman; private static Class<?> ContainerAnvilClass;
private static boolean loadedClasses = false; 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 Player player; private Player player;
@SuppressWarnings("unused")
private AnvilClickEventHandler handler;
private Map<AnvilSlot, ItemStack> items = new HashMap<>(); private Map<AnvilSlot, ItemStack> items = new HashMap<>();
private OnClose onClose = null; private OnClose onClose = null;
private Inventory inv; private Inventory inv;
private Listener listener; private Listener listener;
private Sound closeSound = UltimateModeration.getInstance().isServerVersionAtLeast(ServerVersion.V1_12) ? Sound.ENTITY_PLAYER_LEVELUP : Sound.valueOf("LEVEL_UP"); private Sound closeSound = Sound.ENTITY_PLAYER_LEVELUP;
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");
if (NMSUtil.getVersionNumber() > 13) {
ContainerAccessClass = NMSUtil.getNMSClass("ContainerAccess");
ContainersClass = NMSUtil.getNMSClass("Containers");
}
}
public AbstractAnvilGUI(final Player player, final AnvilClickEventHandler handler) { public AbstractAnvilGUI(final Player player, final AnvilClickEventHandler handler) {
loadClasses();
this.player = player; this.player = player;
this.handler = handler;
this.listener = new Listener() { this.listener = new Listener() {
@EventHandler @EventHandler(priority = EventPriority.LOWEST)
public void onInventoryClick(InventoryClickEvent event) { public void onInventoryClick(InventoryClickEvent event) {
if (!(event.getWhoClicked() instanceof Player) || !event.getInventory().equals(inv)) return; if (event.getWhoClicked() instanceof Player) {
event.setCancelled(true); if (event.getInventory().equals(inv)) {
event.setCancelled(true);
ItemStack item = event.getCurrentItem(); ItemStack item = event.getCurrentItem();
int slot = event.getRawSlot(); int slot = event.getRawSlot();
String name = ""; String name = "";
if (item != null) { if (item != null) {
if (item.hasItemMeta()) { if (item.hasItemMeta()) {
ItemMeta meta = item.getItemMeta(); ItemMeta meta = item.getItemMeta();
if (meta.hasDisplayName()) { if (meta != null && meta.hasDisplayName()) {
name = meta.getDisplayName(); name = meta.getDisplayName();
}
}
}
AnvilClickEvent clickEvent = new AnvilClickEvent(AnvilSlot.bySlot(slot), name);
handler.onAnvilClick(clickEvent);
if (clickEvent.getWillClose()) {
event.getWhoClicked().closeInventory();
}
if (clickEvent.getWillDestroy()) {
destroy();
} }
} }
} }
AnvilClickEvent clickEvent = new AnvilClickEvent(AnvilSlot.bySlot(slot), name);
if (clickEvent.getWillClose()) {
event.getWhoClicked().closeInventory();
}
handler.onAnvilClick(clickEvent);
if (clickEvent.getWillDestroy()) {
destroy();
}
} }
@EventHandler @EventHandler(priority = EventPriority.LOWEST)
public void onInventoryClose(InventoryCloseEvent event) { public void onInventoryClose(InventoryCloseEvent event) {
if (!(event.getPlayer() instanceof Player)) return; if (event.getPlayer() instanceof Player) {
Inventory inv = event.getInventory(); Inventory inv = event.getInventory();
player.setLevel(player.getLevel() - 1); player.setLevel(player.getLevel() - 1);
if (!inv.equals(AbstractAnvilGUI.this.inv)) return; if (inv.equals(inv)) {
inv.clear(); inv.clear();
OnClose onClose = getOnClose(); player.playSound(player.getLocation(), closeSound, 1F, 1F);
player.playSound(player.getLocation(), closeSound, 1F, 1F); Bukkit.getScheduler().scheduleSyncDelayedTask(UltimateModeration.getInstance(), () -> {
Bukkit.getScheduler().scheduleSyncDelayedTask(UltimateModeration.getInstance(), () -> { if (onClose != null) onClose.OnClose(player, inv);
if (onClose != null) onClose.OnClose(player, inv); destroy();
destroy(); }, 1L);
}, 1L);
}
}
} }
@EventHandler @EventHandler(priority = EventPriority.LOWEST)
public void onPlayerQuit(PlayerQuitEvent event) { public void onPlayerQuit(PlayerQuitEvent event) {
if (!event.getPlayer().equals(getPlayer())) return; if (event.getPlayer().equals(getPlayer())) {
player.setLevel(player.getLevel() - 1); player.setLevel(player.getLevel() - 1);
destroy(); destroy();
}
} }
}; };
Bukkit.getPluginManager().registerEvents(listener, UltimateModeration.getInstance()); Bukkit.getPluginManager().registerEvents(listener, UltimateModeration.getInstance());
} }
private void loadClasses() {
if (loadedClasses) return;
BlockPosition = NMSUtil.getNMSClass("BlockPosition");
PacketPlayOutOpenWindow = NMSUtil.getNMSClass("PacketPlayOutOpenWindow");
ContainerAnvil = NMSUtil.getNMSClass("ContainerAnvil");
EntityHuman = NMSUtil.getNMSClass("EntityHuman");
ChatMessage = NMSUtil.getNMSClass("ChatMessage");
loadedClasses = true;
}
public Player getPlayer() { public Player getPlayer() {
return player; return player;
} }
@ -128,49 +145,59 @@ public class AbstractAnvilGUI {
try { try {
Object craftPlayer = NMSUtil.getCraftClass("entity.CraftPlayer").cast(player); Object craftPlayer = NMSUtil.getCraftClass("entity.CraftPlayer").cast(player);
Method getHandleMethod = craftPlayer.getClass().getMethod("getHandle", new Class<?>[0]); Method getHandleMethod = craftPlayer.getClass().getMethod("getHandle");
Object entityPlayer = getHandleMethod.invoke(craftPlayer, new Object[0]); 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; Object container;
if (NMSUtil.getVersionNumber() == 7) { if (NMSUtil.getVersionNumber() > 13) {
container = ContainerAnvil.getConstructor(new Class[]{NMSUtil.getNMSClass("PlayerInventory"), NMSUtil.getNMSClass("World"), Integer.TYPE, Integer.TYPE, Integer.TYPE, EntityHuman}).newInstance(new Object[]{NMSUtil.getFieldObject(entityPlayer, NMSUtil.getField(entityPlayer.getClass(), "inventory", false)), NMSUtil.getFieldObject(entityPlayer, NMSUtil.getField(entityPlayer.getClass(), "world", false)), Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0), entityPlayer}); container = ContainerAnvilClass
.getConstructor(int.class, PlayerInventoryClass, ContainerAccessClass)
.newInstance(7, playerInventory, ContainerAccessClass.getMethod("at", WorldClass, BlockPositionClass).invoke(null, world, blockPosition));
} else { } else {
container = ContainerAnvil.getConstructor(NMSUtil.getNMSClass("PlayerInventory"), NMSUtil.getNMSClass("World"), BlockPosition, EntityHuman).newInstance(NMSUtil.getFieldObject(entityPlayer, NMSUtil.getField(entityPlayer.getClass(), "inventory", false)), NMSUtil.getFieldObject(entityPlayer, NMSUtil.getField(entityPlayer.getClass(), "world", false)), BlockPosition.getConstructor(int.class, int.class, int.class).newInstance(0, 0, 0), entityPlayer); container = ContainerAnvilClass
.getConstructor(PlayerInventoryClass, WorldClass, BlockPositionClass, EntityHumanClass)
.newInstance(playerInventory, world, blockPosition, entityPlayer);
} }
NMSUtil.getField(NMSUtil.getNMSClass("Container"), "checkReachable", true).set(container, false); NMSUtil.getField(ContainerClass, "checkReachable", true).set(container, false);
Method getBukkitViewMethod = container.getClass().getMethod("getBukkitView", new Class<?>[0]); Method getBukkitViewMethod = container.getClass().getMethod("getBukkitView");
Object bukkitView = getBukkitViewMethod.invoke(container); Object bukkitView = getBukkitViewMethod.invoke(container);
Method getTopInventoryMethod = bukkitView.getClass().getMethod("getTopInventory", new Class<?>[0]); Method getTopInventoryMethod = bukkitView.getClass().getMethod("getTopInventory");
inv = (Inventory) getTopInventoryMethod.invoke(bukkitView); inv = (Inventory) getTopInventoryMethod.invoke(bukkitView);
for (AnvilSlot slot : items.keySet()) { for (AnvilSlot slot : items.keySet()) {
inv.setItem(slot.getSlot(), items.get(slot)); inv.setItem(slot.getSlot(), items.get(slot));
} }
Method nextContainerCounterMethod = entityPlayer.getClass().getMethod("nextContainerCounter", new Class<?>[0]); Method nextContainerCounterMethod = entityPlayer.getClass().getMethod("nextContainerCounter");
int c = (int) nextContainerCounterMethod.invoke(entityPlayer); int c = (int) nextContainerCounterMethod.invoke(entityPlayer);
Constructor<?> chatMessageConstructor = ChatMessage.getConstructor(String.class, Object[].class); Constructor<?> chatMessageConstructor = ChatMessageClass.getConstructor(String.class, Object[].class);
Object packet; Object packet;
if (NMSUtil.getVersionNumber() == 7) { if (NMSUtil.getVersionNumber() > 13) {
packet = PacketPlayOutOpenWindow.getConstructor(new Class[]{Integer.TYPE, Integer.TYPE, String.class, Integer.TYPE, Boolean.TYPE, Integer.TYPE}).newInstance(new Object[]{Integer.valueOf(c), Integer.valueOf(8), "Repairing", Integer.valueOf(0), Boolean.valueOf(true), Integer.valueOf(0)}); packet = PacketPlayOutOpenWindowClass
.getConstructor(int.class, ContainersClass, IChatBaseComponentClass)
.newInstance(c, ContainersClass.getField("ANVIL").get(null), chatMessageConstructor.newInstance("Repairing", new Object[]{}));
} else { } else {
packet = PacketPlayOutOpenWindow.getConstructor(int.class, String.class, NMSUtil.getNMSClass("IChatBaseComponent"), int.class).newInstance(c, "minecraft:anvil", chatMessageConstructor.newInstance("Repairing", new Object[]{}), 0); packet = PacketPlayOutOpenWindowClass
.getConstructor(int.class, String.class, IChatBaseComponentClass, int.class)
.newInstance(c, "minecraft:anvil", chatMessageConstructor.newInstance("Repairing", new Object[]{}), 0);
} }
NMSUtil.sendPacket(player, packet); NMSUtil.sendPacket(player, packet);
Field activeContainerField = NMSUtil.getField(EntityHuman, "activeContainer", true); Field activeContainerField = NMSUtil.getField(EntityHumanClass, "activeContainer", true);
if (activeContainerField != null) { if (activeContainerField != null) {
activeContainerField.set(entityPlayer, container); activeContainerField.set(entityPlayer, container);
NMSUtil.getField(NMSUtil.getNMSClass("Container"), "windowId", true).set(activeContainerField.get(entityPlayer), c); NMSUtil.getField(ContainerClass, "windowId", true).set(activeContainerField.get(entityPlayer), c);
Method addSlotListenerMethod = activeContainerField.get(entityPlayer).getClass().getMethod("addSlotListener", ICraftingClass);
Method addSlotListenerMethod = activeContainerField.get(entityPlayer).getClass().getMethod("addSlotListener", NMSUtil.getNMSClass("ICrafting"));
addSlotListenerMethod.invoke(activeContainerField.get(entityPlayer), entityPlayer); addSlotListenerMethod.invoke(activeContainerField.get(entityPlayer), entityPlayer);
} }
} catch (Exception e) { } catch (Exception e) {
@ -179,9 +206,7 @@ public class AbstractAnvilGUI {
} }
public void destroy() { public void destroy() {
onClose = null;
player = null; player = null;
handler = null;
items = null; items = null;
HandlerList.unregisterAll(listener); HandlerList.unregisterAll(listener);
@ -208,7 +233,7 @@ public class AbstractAnvilGUI {
private int slot; private int slot;
private AnvilSlot(int slot) { AnvilSlot(int slot) {
this.slot = slot; this.slot = slot;
} }
@ -227,6 +252,7 @@ public class AbstractAnvilGUI {
} }
} }
@FunctionalInterface
public interface AnvilClickEventHandler { public interface AnvilClickEventHandler {
void onAnvilClick(AnvilClickEvent event); void onAnvilClick(AnvilClickEvent event);
} }
@ -268,4 +294,5 @@ public class AbstractAnvilGUI {
this.destroy = destroy; this.destroy = destroy;
} }
} }
}
}