diff --git a/src/main/java/dev/noah/perplayerkit/PerPlayerKit.java b/src/main/java/dev/noah/perplayerkit/PerPlayerKit.java index 73a08e3..575ad40 100644 --- a/src/main/java/dev/noah/perplayerkit/PerPlayerKit.java +++ b/src/main/java/dev/noah/perplayerkit/PerPlayerKit.java @@ -39,6 +39,7 @@ import dev.noah.perplayerkit.commands.share.ShareKitCommand; import dev.noah.perplayerkit.commands.shortcuts.ShortECCommand; import dev.noah.perplayerkit.commands.shortcuts.ShortKitCommand; +import dev.noah.perplayerkit.gui.configurable.ConfigurableGuiService; import dev.noah.perplayerkit.listeners.*; import dev.noah.perplayerkit.listeners.antiexploit.CommandListener; import dev.noah.perplayerkit.listeners.antiexploit.ShulkerDropItemsListener; @@ -87,6 +88,7 @@ public void onEnable() { new KitManager(this); new KitShareManager(this); new KitRoomDataManager(this); + new ConfigurableGuiService(this); loadPublicKitsIdsFromConfig(); getLogger().info("Public Kit Configuration Loaded"); @@ -209,8 +211,6 @@ public void onEnable() { Bukkit.getPluginManager().registerEvents(new JoinListener(this, updateChecker), this); Bukkit.getPluginManager().registerEvents(new QuitListener(this), this); Bukkit.getPluginManager().registerEvents(new MenuFunctionListener(), this); - Bukkit.getPluginManager().registerEvents(new KitMenuCloseListener(), this); - Bukkit.getPluginManager().registerEvents(new KitRoomSaveListener(), this); Bukkit.getPluginManager().registerEvents(new AutoRekitListener(this), this); Bukkit.getPluginManager().registerEvents(new AboutCommandListener(), this); diff --git a/src/main/java/dev/noah/perplayerkit/commands/kits/EnderchestCommand.java b/src/main/java/dev/noah/perplayerkit/commands/kits/EnderchestCommand.java index 49bf713..75487d1 100644 --- a/src/main/java/dev/noah/perplayerkit/commands/kits/EnderchestCommand.java +++ b/src/main/java/dev/noah/perplayerkit/commands/kits/EnderchestCommand.java @@ -19,16 +19,11 @@ package dev.noah.perplayerkit.commands.kits; import dev.noah.perplayerkit.commands.core.CommandGuards; -import dev.noah.perplayerkit.gui.ItemUtil; -import dev.noah.perplayerkit.util.StyleManager; -import dev.noah.perplayerkit.util.SoundManager; +import dev.noah.perplayerkit.gui.configurable.ConfigurableGuiService; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import org.bukkit.inventory.ItemStack; -import org.ipvp.canvas.Menu; -import org.ipvp.canvas.type.ChestMenu; import org.jetbrains.annotations.NotNull; public class EnderchestCommand implements CommandExecutor { @@ -44,24 +39,6 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command } public void viewOnlyEC(Player player) { - - ItemStack fill = ItemUtil.createGlassPane(); - - Menu menu = ChestMenu.builder(5).title(StyleManager.get().getPrimaryColor() + "View Only Enderchest").build(); - - - for (int i = 0; i < 9; i++) { - menu.getSlot(i).setItem(fill); - } - for (int i = 36; i < 45; i++) { - menu.getSlot(i).setItem(fill); - } -// set the items in the inventory to the items in the enderchest - ItemStack[] items = player.getEnderChest().getContents(); - for (int i = 0; i < 27; i++) { - menu.getSlot(i + 9).setItem(items[i]); - } - menu.open(player); - SoundManager.playOpenGui(player); + ConfigurableGuiService.get().openViewOnlyEnderchest(player); } } diff --git a/src/main/java/dev/noah/perplayerkit/gui/GUI.java b/src/main/java/dev/noah/perplayerkit/gui/GUI.java index 52a5afe..fb2d28a 100644 --- a/src/main/java/dev/noah/perplayerkit/gui/GUI.java +++ b/src/main/java/dev/noah/perplayerkit/gui/GUI.java @@ -18,39 +18,24 @@ */ package dev.noah.perplayerkit.gui; -import dev.noah.perplayerkit.ItemFilter; -import dev.noah.perplayerkit.KitManager; -import dev.noah.perplayerkit.KitRoomDataManager; -import dev.noah.perplayerkit.PublicKit; -import dev.noah.perplayerkit.util.*; -import net.md_5.bungee.api.ChatColor; -import org.bukkit.Material; +import dev.noah.perplayerkit.gui.configurable.ConfigurableGuiService; import org.bukkit.entity.Player; -import org.bukkit.event.inventory.ClickType; -import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import org.ipvp.canvas.Menu; -import org.ipvp.canvas.slot.Slot; import java.util.HashMap; import java.util.HashSet; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.UUID; -import static dev.noah.perplayerkit.gui.ItemUtil.addHideFlags; -import static dev.noah.perplayerkit.gui.ItemUtil.createItem; -import static dev.noah.perplayerkit.gui.ItemUtil.createGlassPane; -import static dev.noah.perplayerkit.gui.GuiLayoutUtils.*; -import static dev.noah.perplayerkit.util.PlayerUtil.getPlayerName; - public class GUI { - private final Plugin plugin; - private final boolean filterItemsOnImport; private static final Set kitDeletionFlag = new HashSet<>(); private static final Map inspectTargets = new HashMap<>(); + public GUI(Plugin plugin) { + } + public static void setInspectTarget(UUID inspector, UUID target) { inspectTargets.put(inspector, target); } @@ -59,554 +44,53 @@ public static UUID getAndRemoveInspectTarget(UUID inspector) { return inspectTargets.remove(inspector); } - public GUI(Plugin plugin) { - this.plugin = plugin; - this.filterItemsOnImport = plugin.getConfig().getBoolean("anti-exploit.import-filter", false); - } - - public static void addLoadPublicKit(Slot slot, String id) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - KitManager.get().loadPublicKit(player, id); - info.getClickedMenu().close(); - }); - } - public static boolean removeKitDeletionFlag(Player player) { return kitDeletionFlag.remove(player.getUniqueId()); } - public void OpenKitMenu(Player p, int slot) { - Menu menu = GuiMenuFactory.createKitMenu(slot); - - if (KitManager.get().getItemStackArrayById(p.getUniqueId().toString() + slot) != null) { - ItemStack[] kit = KitManager.get().getItemStackArrayById(p.getUniqueId().toString() + slot); - for (int i = 0; i < KIT_CONTENT_END; i++) { - menu.getSlot(i).setItem(kit[i]); - } - } - allowModificationRange(menu, 0, KIT_CONTENT_END); - setGlassPaneRange(menu, KIT_CONTENT_END, MENU_SIZE); - setArmorAndOffhandIndicators(menu); - - menu.getSlot(IMPORT_SLOT).setItem(createItem(Material.CHEST, 1, "IMPORT", "● Import from inventory")); - menu.getSlot(CLEAR_SLOT).setItem(createItem(Material.BARRIER, 1, "CLEAR KIT", "● Shift click to clear")); - menu.getSlot(BACK_SLOT).setItem(createItem(Material.OAK_DOOR, 1, "BACK")); - addMainButton(menu.getSlot(BACK_SLOT)); - addClear(menu.getSlot(CLEAR_SLOT)); - addImport(menu.getSlot(IMPORT_SLOT)); - menu.setCursorDropHandler(Menu.ALLOW_CURSOR_DROPPING); - - menu.open(p); + public void OpenKitMenu(Player player, int slot) { + ConfigurableGuiService.get().openPlayerKitEditor(player, slot); } - public void OpenPublicKitEditor(Player p, String kitId) { - Menu menu = GuiMenuFactory.createPublicKitMenu(kitId); - - if (KitManager.get().getItemStackArrayById(IDUtil.getPublicKitId(kitId)) != null) { - ItemStack[] kit = KitManager.get().getItemStackArrayById(IDUtil.getPublicKitId(kitId)); - for (int i = 0; i < KIT_CONTENT_END; i++) { - menu.getSlot(i).setItem(kit[i]); - } - } - allowModificationRange(menu, 0, KIT_CONTENT_END); - setGlassPaneRange(menu, KIT_CONTENT_END, MENU_SIZE); - setArmorAndOffhandIndicators(menu); - - menu.getSlot(IMPORT_SLOT).setItem(createItem(Material.CHEST, 1, "IMPORT", "● Import from inventory")); - menu.getSlot(CLEAR_SLOT).setItem(createItem(Material.BARRIER, 1, "CLEAR KIT", "● Shift click to clear")); - menu.getSlot(BACK_SLOT).setItem(createItem(Material.OAK_DOOR, 1, "BACK")); - addMainButton(menu.getSlot(BACK_SLOT)); - addClear(menu.getSlot(CLEAR_SLOT)); - addImport(menu.getSlot(IMPORT_SLOT)); - menu.setCursorDropHandler(Menu.ALLOW_CURSOR_DROPPING); - - menu.open(p); + public void OpenPublicKitEditor(Player player, String kitId) { + ConfigurableGuiService.get().openPublicKitEditor(player, kitId); } - public void OpenECKitKenu(Player p, int slot) { - Menu menu = GuiMenuFactory.createECMenu(slot); - - setGlassPaneRange(menu, 0, EC_CONTENT_START); - setGlassPaneRange(menu, EC_CONTENT_END, MENU_SIZE); - if (KitManager.get().getItemStackArrayById(p.getUniqueId() + "ec" + slot) != null) { - - ItemStack[] kit = KitManager.get().getItemStackArrayById(p.getUniqueId() + "ec" + slot); - for (int i = EC_CONTENT_START; i < EC_CONTENT_END; i++) { - menu.getSlot(i).setItem(kit[i - EC_CONTENT_START]); - } - } - allowModificationRange(menu, EC_CONTENT_START, EC_CONTENT_END); - menu.getSlot(IMPORT_SLOT).setItem(createItem(Material.ENDER_CHEST, 1, "IMPORT", "● Import from enderchest")); - menu.getSlot(CLEAR_SLOT).setItem(createItem(Material.BARRIER, 1, "CLEAR KIT", "● Shift click to clear")); - menu.getSlot(BACK_SLOT).setItem(createItem(Material.OAK_DOOR, 1, "BACK")); - addMainButton(menu.getSlot(BACK_SLOT)); - addClear(menu.getSlot(CLEAR_SLOT), EC_CONTENT_START, EC_CONTENT_END); - addImportEC(menu.getSlot(IMPORT_SLOT)); - menu.setCursorDropHandler(Menu.ALLOW_CURSOR_DROPPING); - menu.open(p); + public void OpenECKitKenu(Player player, int slot) { + ConfigurableGuiService.get().openEnderchestEditor(player, slot); } - public void InspectKit(Player p, UUID target, int slot) { - setInspectTarget(p.getUniqueId(), target); - String playerName = getPlayerName(target); - Menu menu = GuiMenuFactory.createInspectMenu(slot, playerName); - - if (KitManager.get().hasKit(target, slot)) { - ItemStack[] kit = KitManager.get().getItemStackArrayById(target.toString() + slot); - for (int i = 0; i < KIT_CONTENT_END; i++) { - menu.getSlot(i).setItem(kit[i]); - } - } - setGlassPaneRange(menu, KIT_CONTENT_END, MENU_SIZE); - setArmorAndOffhandIndicators(menu); - - menu.getSlot(BACK_SLOT).setItem(createItem(Material.OAK_DOOR, 1, "CLOSE")); - menu.getSlot(BACK_SLOT).setClickHandler((player, info) -> { - SoundManager.playClick(player); - info.getClickedMenu().close(); - SoundManager.playCloseGui(player); - }); - - if (p.hasPermission("perplayerkit.admin")) { - allowModificationRange(menu, 0, KIT_CONTENT_END); - menu.getSlot(CLEAR_SLOT).setItem(createItem(Material.BARRIER, 1, "CLEAR KIT", "● Shift click to delete kit")); - addClearKit(menu.getSlot(CLEAR_SLOT), target, slot); - } - - menu.setCursorDropHandler(Menu.ALLOW_CURSOR_DROPPING); - menu.open(p); - SoundManager.playOpenGui(p); + public void InspectKit(Player player, UUID target, int slot) { + setInspectTarget(player.getUniqueId(), target); + ConfigurableGuiService.get().openInspectKit(player, target, slot); } - public void InspectEc(Player p, UUID target, int slot) { - setInspectTarget(p.getUniqueId(), target); - String playerName = getPlayerName(target); - if (playerName == null) { - playerName = target.toString(); - } - Menu menu = GuiMenuFactory.createInspectEcMenu(slot, playerName); - - setGlassPaneRange(menu, 0, EC_CONTENT_START); - setGlassPaneRange(menu, EC_CONTENT_END, MENU_SIZE); - if (KitManager.get().getItemStackArrayById(target + "ec" + slot) != null) { - - ItemStack[] kit = KitManager.get().getItemStackArrayById(target + "ec" + slot); - for (int i = EC_CONTENT_START; i < EC_CONTENT_END; i++) { - menu.getSlot(i).setItem(kit[i - EC_CONTENT_START]); - } - } - - menu.getSlot(BACK_SLOT).setItem(createItem(Material.OAK_DOOR, 1, "CLOSE")); - menu.getSlot(BACK_SLOT).setClickHandler((player, info) -> { - SoundManager.playClick(player); - info.getClickedMenu().close(); - SoundManager.playCloseGui(player); - }); - - if (p.hasPermission("perplayerkit.admin")) { - allowModificationRange(menu, EC_CONTENT_START, EC_CONTENT_END); - menu.getSlot(CLEAR_SLOT).setItem(createItem(Material.BARRIER, 1, "CLEAR ENDERCHEST", "● Shift click to delete enderchest")); - addClearEnderchest(menu.getSlot(CLEAR_SLOT), target, slot); - } - - menu.setCursorDropHandler(Menu.ALLOW_CURSOR_DROPPING); - menu.open(p); - SoundManager.playOpenGui(p); + public void InspectEc(Player player, UUID target, int slot) { + setInspectTarget(player.getUniqueId(), target); + ConfigurableGuiService.get().openInspectEnderchest(player, target, slot); } - public void OpenMainMenu(Player p) { - Menu menu = GuiMenuFactory.createMainMenu(p); - for (int i = 0; i < MENU_SIZE; i++) { - menu.getSlot(i).setItem(createGlassPane()); - } - for (int i = 9; i < 18; i++) { - menu.getSlot(i).setItem(createItem(Material.CHEST, 1, "Kit " + (i - 8) + "", "● Left click to load kit", "● Right click to edit kit")); - addEditLoad(menu.getSlot(i), i - 8); - } - for (int i = 18; i < 27; i++) { - if (KitManager.get().getItemStackArrayById(p.getUniqueId() + "ec" + (i - 17)) != null) { - menu.getSlot(i).setItem(createItem(Material.ENDER_CHEST, 1, "Enderchest " + (i - 17) + "", "● Left click to load kit", "● Right click to edit kit")); - addEditLoadEC(menu.getSlot(i), i - 17); - } else { - menu.getSlot(i).setItem(createItem(Material.ENDER_EYE, 1, "Enderchest " + (i - 17) + "", "● Click to create")); - addEditEC(menu.getSlot(i), i - 17); - } - } - for (int i = 27; i < 36; i++) { - if (KitManager.get().getItemStackArrayById(p.getUniqueId().toString() + (i - 26)) != null) { - menu.getSlot(i).setItem(createItem(Material.KNOWLEDGE_BOOK, 1, "KIT EXISTS", "● Click to edit")); - } else { - menu.getSlot(i).setItem(createItem(Material.BOOK, 1, "KIT NOT FOUND", "● Click to create")); - } - addEdit(menu.getSlot(i), i - 26); - } - - for (int i = 37; i < 44; i++) { - menu.getSlot(i).setItem(createGlassPane()); - } - - menu.getSlot(37).setItem(createItem(Material.NETHER_STAR, 1, "KIT ROOM")); - menu.getSlot(38).setItem(createItem(Material.BOOKSHELF, 1, "PREMADE KITS")); - menu.getSlot(39).setItem(createItem(Material.OAK_SIGN, 1, "INFO", "● Click a kit slot to load your kit", "● Right click or click the book to edit", "● Share kits with /sharekit ")); - menu.getSlot(41).setItem(createItem(Material.REDSTONE_BLOCK, 1, "CLEAR INVENTORY", "● Shift click")); - menu.getSlot(42).setItem(createItem(Material.COMPASS, 1, "SHARE KITS", "● /sharekit ")); - menu.getSlot(43).setItem(createItem(Material.EXPERIENCE_BOTTLE, 1, "REPAIR ITEMS")); - addRepairButton(menu.getSlot(43)); - addKitRoom(menu.getSlot(37)); - addPublicKitMenu(menu.getSlot(38)); - addClearButton(menu.getSlot(41)); - - menu.setCursorDropHandler(Menu.ALLOW_CURSOR_DROPPING); - menu.open(p); + public void OpenMainMenu(Player player) { + ConfigurableGuiService.get().openMainMenu(player); } - public void OpenKitRoom(Player p) { - OpenKitRoom(p, 0); + public void OpenKitRoom(Player player) { + ConfigurableGuiService.get().openKitRoom(player); } - public void OpenKitRoom(Player p, int page) { - Menu menu = GuiMenuFactory.createKitRoomMenu(); - allowModificationRange(menu, 0, FOOTER_START); - setGlassPaneRange(menu, FOOTER_START, MENU_SIZE); - if (KitRoomDataManager.get().getKitRoomPage(page) != null) { - for (int i = 0; i < FOOTER_START; i++) { - menu.getSlot(i).setItem(KitRoomDataManager.get().getKitRoomPage(page)[i]); - } - } - - menu.getSlot(45).setItem(createItem(Material.BEACON, 1, "REFILL")); - addKitRoom(menu.getSlot(45), page); - - if (!p.hasPermission("perplayerkit.editkitroom")) { - menu.getSlot(53).setItem(createItem(Material.OAK_DOOR, 1, "BACK")); - addMainButton(menu.getSlot(53)); - } else { - menu.getSlot(53).setItem(createItem(Material.BARRIER, page + 1, "EDIT MENU", "SHIFT RIGHT CLICK TO SAVE")); - } - addKitRoom(menu.getSlot(47), 0); - addKitRoom(menu.getSlot(48), 1); - addKitRoom(menu.getSlot(49), 2); - addKitRoom(menu.getSlot(50), 3); - addKitRoom(menu.getSlot(51), 4); - - for (int i = 1; i < 6; i++) { - menu.getSlot(46 + i).setItem(addHideFlags(createItem(Material.valueOf(plugin.getConfig().getString("kitroom.items." + i + ".material")), "" + plugin.getConfig().getString("kitroom.items." + i + ".name")))); - } - - menu.getSlot(page + 47).setItem(ItemUtil.addEnchantLook(menu.getSlot(page + 47).getItem(p))); - - menu.setCursorDropHandler(Menu.ALLOW_CURSOR_DROPPING); - menu.open(p); + public void OpenKitRoom(Player player, int page) { + ConfigurableGuiService.get().openKitRoom(player, page); } - public Menu ViewPublicKitMenu(Player p, String id) { - ItemStack[] kit = KitManager.get().getPublicKit(id); - - if (kit == null) { - p.sendMessage(ChatColor.RED + "Kit not found"); - if (p.hasPermission("perplayerkit.admin")) { - p.sendMessage(ChatColor.RED + "To assign a kit to this publickit use /savepublickit "); - } - return null; - } - Menu menu = GuiMenuFactory.createViewPublicKitMenu(id); - - for (int i = 0; i < MENU_SIZE; i++) { - menu.getSlot(i).setItem(ItemUtil.createGlassPane()); - } - - for (int i = 9; i < 36; i++) { - menu.getSlot(i).setItem(kit[i]); - } - for (int i = 0; i < 9; i++) { - menu.getSlot(i + 36).setItem(kit[i]); + public Menu ViewPublicKitMenu(Player player, String id) { + Menu menu = ConfigurableGuiService.get().createPublicKitViewer(player, id); + if (menu != null) { + menu.open(player); } - for (int i = 36; i < 41; i++) { - menu.getSlot(i + 9).setItem(kit[i]); - } - - setArmorAndOffhandIndicators(menu); - menu.getSlot(LOAD_PUBLIC_KIT_SLOT).setItem(createItem(Material.APPLE, 1, "LOAD KIT")); - menu.getSlot(BACK_SLOT).setItem(createItem(Material.OAK_DOOR, 1, "BACK")); - addPublicKitMenu(menu.getSlot(BACK_SLOT)); - addLoadPublicKit(menu.getSlot(LOAD_PUBLIC_KIT_SLOT), id); - - menu.open(p); - return menu; } public void OpenPublicKitMenu(Player player) { - Menu menu = GuiMenuFactory.createPublicKitRoomMenu(); - for (int i = 0; i < MENU_SIZE; i++) { - menu.getSlot(i).setItem(ItemUtil.createGlassPane()); - } - - for (int i = 18; i < 36; i++) { - menu.getSlot(i).setItem(ItemUtil.createItem(Material.BOOK, 1, "MORE KITS COMING SOON")); - } - - List publicKitList = KitManager.get().getPublicKitList(); - - for (int i = 0; i < publicKitList.size(); i++) { - if (KitManager.get().hasPublicKit(publicKitList.get(i).id)) { - if (player.hasPermission("perplayerkit.admin")) { - menu.getSlot(i + 18).setItem(createItem(publicKitList.get(i).icon, 1, ChatColor.RESET + publicKitList.get(i).name, "● [ADMIN] Shift click to edit")); - } else { - menu.getSlot(i + 18).setItem(createItem(publicKitList.get(i).icon, 1, ChatColor.RESET + publicKitList.get(i).name)); - } - addPublicKitButton(menu.getSlot(i + 18), publicKitList.get(i).id); - } else { - if (player.hasPermission("perplayerkit.admin")) { - menu.getSlot(i + 18).setItem(createItem(publicKitList.get(i).icon, 1, ChatColor.RESET + publicKitList.get(i).name + " [UNASSIGNED]", "● Admins have not yet setup this kit yet", "● [ADMIN] Shift click to edit")); - } else { - menu.getSlot(i + 18).setItem(createItem(publicKitList.get(i).icon, 1, ChatColor.RESET + publicKitList.get(i).name + " [UNASSIGNED]", "● Admins have not yet setup this kit yet")); - } - } - - if (player.hasPermission("perplayerkit.admin")) { - addAdminPublicKitButton(menu.getSlot(i + 18), publicKitList.get(i).id); - } - } - - addMainButton(menu.getSlot(BACK_SLOT)); - menu.getSlot(BACK_SLOT).setItem(createItem(Material.OAK_DOOR, 1, "BACK")); - menu.open(player); - } - - public void addClear(Slot slot) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - if (info.getClickType().isShiftClick()) { - Menu m = info.getClickedMenu(); - for (int i = 0; i < 41; i++) { - m.getSlot(i).setItem((org.bukkit.inventory.ItemStack) null); - } - } - }); - } - - public void addClear(Slot slot, int start, int end) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - if (info.getClickType().isShiftClick()) { - Menu m = info.getClickedMenu(); - for (int i = start; i < end; i++) { - m.getSlot(i).setItem((org.bukkit.inventory.ItemStack) null); - } - } - }); - } - - public void addClearKit(Slot slot, UUID target, int slotNum) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - if (info.getClickType().isShiftClick()) { - KitManager.get().deleteKit(target, slotNum); - player.sendMessage(ChatColor.GREEN + "Kit " + slotNum + " deleted for player!"); - SoundManager.playSuccess(player); - kitDeletionFlag.add(player.getUniqueId()); - info.getClickedMenu().close(); - SoundManager.playCloseGui(player); - } - }); - } - - public void addClearEnderchest(Slot slot, UUID target, int slotNum) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - if (info.getClickType().isShiftClick()) { - KitManager.get().deleteEnderchest(target, slotNum); - player.sendMessage(ChatColor.GREEN + "Enderchest " + slotNum + " deleted for player!"); - SoundManager.playSuccess(player); - kitDeletionFlag.add(player.getUniqueId()); - info.getClickedMenu().close(); - SoundManager.playCloseGui(player); - } - }); - } - - public void addPublicKitButton(Slot slot, String id) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - if (info.getClickType() == ClickType.LEFT) { - KitManager.get().loadPublicKit(player, id); - info.getClickedMenu().close(); - } else if (info.getClickType() == ClickType.RIGHT) { - Menu m = ViewPublicKitMenu(player, id); - if (m != null) { - m.open(player); - } - } - }); - } - - public void addAdminPublicKitButton(Slot slot, String id) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - if (info.getClickType().isShiftClick()) { - OpenPublicKitEditor(player, id); - return; - } - if (info.getClickType() == ClickType.LEFT) { - KitManager.get().loadPublicKit(player, id); - } else if (info.getClickType() == ClickType.RIGHT) { - Menu m = ViewPublicKitMenu(player, id); - if (m != null) { - m.open(player); - } - } - }); - } - - public void addMainButton(Slot slot) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - OpenMainMenu(player); - }); - } - - public void addKitRoom(Slot slot) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - OpenKitRoom(player); - BroadcastManager.get().broadcastPlayerOpenedKitRoom(player); - }); - } - - public void addKitRoom(Slot slot, int page) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - OpenKitRoom(player, page); - }); - } - - public void addPublicKitMenu(Slot slot) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - OpenPublicKitMenu(player); - }); - } - - public void addKitRoomSaveButton(Slot slot, int page) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - if (info.getClickType().isRightClick() && info.getClickType().isShiftClick()) { - ItemStack[] data = new ItemStack[45]; - for (int i = 0; i < 41; i++) { - data[i] = player.getInventory().getContents()[i]; - } - KitRoomDataManager.get().setKitRoom(page, data); - player.sendMessage("saved menu"); - SoundManager.playSuccess(player); - } - }); - } - - public void addRepairButton(Slot slot) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - BroadcastManager.get().broadcastPlayerRepaired(player); - PlayerUtil.repairAll(player); - player.updateInventory(); - SoundManager.playSuccess(player); - }); - } - - public void addClearButton(Slot slot) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - if (info.getClickType().isShiftClick()) { - player.getInventory().clear(); - player.sendMessage(ChatColor.GREEN + "Inventory cleared"); - SoundManager.playSuccess(player); - } - }); - } - - public void addImport(Slot slot) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - Menu m = info.getClickedMenu(); - ItemStack[] inv; - if (filterItemsOnImport) { - inv = ItemFilter.get().filterItemStack(player.getInventory().getContents()); - } else { - inv = player.getInventory().getContents(); - } - for (int i = 0; i < 41; i++) { - m.getSlot(i).setItem(inv[i]); - } - }); - } - - public void addImportEC(Slot slot) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - Menu m = info.getClickedMenu(); - ItemStack[] inv; - if (filterItemsOnImport) { - inv = ItemFilter.get().filterItemStack(player.getEnderChest().getContents()); - } else { - inv = player.getEnderChest().getContents(); - } - for (int i = 0; i < 27; i++) { - m.getSlot(i + 9).setItem(inv[i]); - } - }); - } - - public void addEdit(Slot slot, int i) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - if (info.getClickType().isLeftClick() || info.getClickType().isRightClick()) { - OpenKitMenu(player, i); - } - }); - } - - public void addEditEC(Slot slot, int i) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - if (info.getClickType().isLeftClick() || info.getClickType().isRightClick()) { - OpenECKitKenu(player, i); - } - }); - } - - public void addLoad(Slot slot, int i) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - if (info.getClickType() == ClickType.LEFT || info.getClickType() == ClickType.SHIFT_LEFT) { - KitManager.get().loadKit(player, i); - info.getClickedMenu().close(); - SoundManager.playCloseGui(player); - } - }); - } - - public void addEditLoad(Slot slot, int i) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - if (info.getClickType() == ClickType.LEFT || info.getClickType() == ClickType.SHIFT_LEFT) { - KitManager.get().loadKit(player, i); - info.getClickedMenu().close(); - } else if (info.getClickType() == ClickType.RIGHT || info.getClickType() == ClickType.SHIFT_RIGHT) { - OpenKitMenu(player, i); - } - }); - } - - public void addEditLoadEC(Slot slot, int i) { - slot.setClickHandler((player, info) -> { - SoundManager.playClick(player); - if (info.getClickType() == ClickType.LEFT || info.getClickType() == ClickType.SHIFT_LEFT) { - KitManager.get().loadEnderchest(player, i); - info.getClickedMenu().close(); - } else if (info.getClickType() == ClickType.RIGHT || info.getClickType() == ClickType.SHIFT_RIGHT) { - OpenECKitKenu(player, i); - } - }); + ConfigurableGuiService.get().openPublicKitMenu(player); } } diff --git a/src/main/java/dev/noah/perplayerkit/gui/configurable/ConfigurableGuiService.java b/src/main/java/dev/noah/perplayerkit/gui/configurable/ConfigurableGuiService.java new file mode 100644 index 0000000..bcd137c --- /dev/null +++ b/src/main/java/dev/noah/perplayerkit/gui/configurable/ConfigurableGuiService.java @@ -0,0 +1,1113 @@ +package dev.noah.perplayerkit.gui.configurable; + +import dev.noah.perplayerkit.ItemFilter; +import dev.noah.perplayerkit.KitManager; +import dev.noah.perplayerkit.KitRoomDataManager; +import dev.noah.perplayerkit.PublicKit; +import dev.noah.perplayerkit.gui.ItemUtil; +import dev.noah.perplayerkit.util.BroadcastManager; +import dev.noah.perplayerkit.util.IDUtil; +import dev.noah.perplayerkit.util.PlayerUtil; +import dev.noah.perplayerkit.util.SoundManager; +import dev.noah.perplayerkit.util.StyleManager; +import me.clip.placeholderapi.PlaceholderAPI; +import net.md_5.bungee.api.ChatColor; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.OfflinePlayer; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.plugin.Plugin; +import org.ipvp.canvas.Menu; +import org.ipvp.canvas.slot.ClickOptions; +import org.ipvp.canvas.slot.Slot; +import org.ipvp.canvas.type.ChestMenu; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class ConfigurableGuiService { + private static final Pattern PLACEHOLDER_PATTERN = Pattern.compile("%([a-zA-Z0-9_]+)%"); + + private static ConfigurableGuiService instance; + + private final Plugin plugin; + private final GuiConfigManager guiConfigManager; + + public ConfigurableGuiService(Plugin plugin) { + this.plugin = plugin; + this.guiConfigManager = new GuiConfigManager(plugin); + instance = this; + } + + public static ConfigurableGuiService get() { + if (instance == null) { + throw new IllegalStateException("ConfigurableGuiService has not been initialized"); + } + return instance; + } + + public void openMainMenu(Player player) { + openConfiguredGui("main-menu", player, GuiContext.empty()); + } + + public void openPlayerKitEditor(Player player, int slot) { + openConfiguredGui("player-kit-editor", player, GuiContext.empty() + .with("slot", slot) + .with("slot_display", slot)); + } + + public void openPublicKitEditor(Player player, String publicKitId) { + openConfiguredGui("public-kit-editor", player, enrichPublicKitContext(GuiContext.empty(), publicKitId)); + } + + public void openEnderchestEditor(Player player, int slot) { + openConfiguredGui("enderchest-editor", player, GuiContext.empty() + .with("slot", slot) + .with("slot_display", slot)); + } + + public void openInspectKit(Player player, UUID targetUuid, int slot) { + openConfiguredGui("inspect-kit", player, GuiContext.empty() + .with("slot", slot) + .with("slot_display", slot) + .with("target_uuid", targetUuid) + .with("target_name", getPlayerName(targetUuid))); + } + + public void openInspectEnderchest(Player player, UUID targetUuid, int slot) { + openConfiguredGui("inspect-enderchest", player, GuiContext.empty() + .with("slot", slot) + .with("slot_display", slot) + .with("target_uuid", targetUuid) + .with("target_name", getPlayerName(targetUuid))); + } + + public void openPublicKitMenu(Player player) { + openConfiguredGui("public-kit-menu", player, GuiContext.empty()); + } + + public void openKitRoom(Player player) { + openKitRoom(player, 0); + } + + public void openKitRoom(Player player, int page) { + openConfiguredGui("kit-room", player, GuiContext.empty() + .with("page", page) + .with("page_display", page + 1)); + } + + public Menu createPublicKitViewer(Player player, String publicKitId) { + if (KitManager.get().getPublicKit(publicKitId) == null) { + player.sendMessage(ChatColor.RED + "Kit not found"); + if (player.hasPermission("perplayerkit.admin")) { + player.sendMessage(ChatColor.RED + "To assign a kit to this publickit use /savepublickit "); + } + return null; + } + return createMenu("public-kit-viewer", player, enrichPublicKitContext(GuiContext.empty(), publicKitId)); + } + + public void openViewOnlyEnderchest(Player player) { + openConfiguredGui("view-only-enderchest", player, GuiContext.empty()); + } + + public Menu createMenu(String guiId, Player viewer, GuiContext context) { + ConfigurationSection guiSection = guiConfigManager.getGuiSection(guiId); + if (guiSection == null) { + plugin.getLogger().warning("Missing GUI definition: " + guiId); + return null; + } + + int rows = Math.max(1, Math.min(6, guiSection.getInt("rows", 6))); + String title = resolveText(guiSection.getString("title", "Menu"), viewer, context); + + Menu menu = ChestMenu.builder(rows) + .title(title) + .redraw(guiSection.getBoolean("redraw", false)) + .build(); + + menu.setCursorDropHandler(Menu.ALLOW_CURSOR_DROPPING); + + AtomicBoolean skipCloseSave = new AtomicBoolean(false); + applyCloseHandler(guiId, menu, context, skipCloseSave); + + for (ConfigurationSection elementSection : getOrderedElementSections(guiSection)) { + renderElement(menu, viewer, guiId, context, elementSection, skipCloseSave); + } + + return menu; + } + + private Menu openConfiguredGui(String guiId, Player viewer, GuiContext context) { + Menu menu = createMenu(guiId, viewer, context); + if (menu == null) { + return null; + } + + menu.open(viewer); + SoundManager.playOpenGui(viewer); + return menu; + } + + private void renderElement(Menu menu, Player viewer, String guiId, GuiContext context, ConfigurationSection elementSection, AtomicBoolean skipCloseSave) { + if (!isVisibleToViewer(elementSection, viewer)) { + return; + } + + String type = elementSection.getString("type", "static").toLowerCase(Locale.ROOT); + switch (type) { + case "fill": + case "static": + case "button": + renderStaticElement(menu, viewer, context, elementSection, skipCloseSave); + return; + case "component": + renderComponent(menu, viewer, guiId, context, elementSection, skipCloseSave); + return; + default: + plugin.getLogger().warning("Unknown GUI element type '" + type + "'"); + } + } + + private void renderStaticElement(Menu menu, Player viewer, GuiContext context, ConfigurationSection elementSection, AtomicBoolean skipCloseSave) { + List slots = parseSlots(elementSection.get("slots")); + ConfigurationSection itemSection = elementSection.getConfigurationSection("item"); + ConfigurationSection actionsSection = elementSection.getConfigurationSection("actions"); + boolean editable = elementSection.getBoolean("editable", false); + + for (int slotIndex : slots) { + Slot slot = menu.getSlot(slotIndex); + ItemStack item = buildItem(itemSection, viewer, context); + if (item != null) { + slot.setItem(item); + } + if (editable) { + allowModification(slot); + } + bindActions(slot, actionsSection, context, skipCloseSave); + } + } + + private void renderComponent(Menu menu, Player viewer, String guiId, GuiContext context, ConfigurationSection elementSection, AtomicBoolean skipCloseSave) { + String component = elementSection.getString("component", "").toLowerCase(Locale.ROOT); + List slots = parseSlots(elementSection.get("slots")); + + switch (component) { + case "player-kit-selector": + renderIndexedVariantComponent(menu, viewer, slots, elementSection, context, skipCloseSave, "default", false, false); + return; + case "enderchest-selector": + renderIndexedVariantComponent(menu, viewer, slots, elementSection, context, skipCloseSave, null, false, true); + return; + case "kit-status-selector": + renderIndexedVariantComponent(menu, viewer, slots, elementSection, context, skipCloseSave, null, true, false); + return; + case "public-kit-list": + renderPublicKitList(menu, viewer, elementSection, context, slots, skipCloseSave); + return; + case "kit-data": + renderItemData(menu, viewer, slots, resolveKitData(viewer, context), elementSection.getBoolean("editable", false)); + return; + case "enderchest-data": + renderItemData(menu, viewer, slots, resolveEnderchestData(viewer, context), elementSection.getBoolean("editable", false)); + return; + case "player-enderchest-data": + renderItemData(menu, viewer, slots, viewer.getEnderChest().getContents(), elementSection.getBoolean("editable", false)); + return; + case "kit-room-data": + renderItemData(menu, viewer, slots, resolveKitRoomData(context), elementSection.getBoolean("editable", false)); + return; + case "kit-room-category-buttons": + renderKitRoomCategoryButtons(menu, viewer, slots, elementSection, context, skipCloseSave); + return; + case "kit-room-control": + renderKitRoomControl(menu, viewer, elementSection, context, skipCloseSave); + return; + default: + plugin.getLogger().warning("Unknown GUI component '" + component + "'"); + } + } + + private void renderIndexedVariantComponent(Menu menu, Player viewer, List slots, ConfigurationSection elementSection, GuiContext baseContext, AtomicBoolean skipCloseSave, String fallbackVariant, boolean playerKitExists, boolean enderchestExists) { + int startIndex = elementSection.getInt("start-index", 1); + + for (int i = 0; i < slots.size(); i++) { + int slotNumber = startIndex + i; + GuiContext slotContext = baseContext + .with("slot", slotNumber) + .with("slot_display", slotNumber); + + String variant = fallbackVariant; + if (playerKitExists) { + variant = KitManager.get().hasKit(viewer.getUniqueId(), slotNumber) ? "exists" : "missing"; + } else if (enderchestExists) { + variant = KitManager.get().hasEC(viewer.getUniqueId(), slotNumber) ? "exists" : "missing"; + } + + applyVariant(menu.getSlot(slots.get(i)), viewer, elementSection, variant, slotContext, skipCloseSave); + } + } + + private void renderPublicKitList(Menu menu, Player viewer, ConfigurationSection elementSection, GuiContext baseContext, List slots, AtomicBoolean skipCloseSave) { + List publicKits = KitManager.get().getPublicKitList(); + boolean admin = viewer.hasPermission("perplayerkit.admin"); + + for (int i = 0; i < Math.min(slots.size(), publicKits.size()); i++) { + PublicKit publicKit = publicKits.get(i); + boolean assigned = KitManager.get().hasPublicKit(publicKit.id); + String variant; + + if (admin) { + variant = assigned ? "admin_assigned" : "admin_unassigned"; + } else { + variant = assigned ? "assigned" : "unassigned"; + } + + GuiContext slotContext = baseContext + .with("public_kit_id", publicKit.id) + .with("public_kit_name", publicKit.name) + .with("public_kit_icon", publicKit.icon); + + applyVariant(menu.getSlot(slots.get(i)), viewer, elementSection, variant, slotContext, skipCloseSave); + } + } + + private void renderKitRoomCategoryButtons(Menu menu, Player viewer, List slots, ConfigurationSection elementSection, GuiContext baseContext, AtomicBoolean skipCloseSave) { + int currentPage = getRequiredInt(baseContext, "page", 0); + int startPage = elementSection.getInt("start-page", 0); + + for (int i = 0; i < slots.size(); i++) { + int page = startPage + i; + String basePath = "kitroom.items." + (page + 1); + String name = plugin.getConfig().getString(basePath + ".name", "Page " + (page + 1)); + Material material = resolveMaterialName(plugin.getConfig().getString(basePath + ".material", "BOOK"), Material.BOOK); + + GuiContext slotContext = baseContext + .with("page", page) + .with("page_display", page + 1) + .with("kitroom_name", name) + .with("kitroom_material", material); + + String variant = page == currentPage ? "active" : "default"; + applyVariant(menu.getSlot(slots.get(i)), viewer, elementSection, variant, slotContext, skipCloseSave); + } + } + + private void renderKitRoomControl(Menu menu, Player viewer, ConfigurationSection elementSection, GuiContext context, AtomicBoolean skipCloseSave) { + List slots = parseSlots(elementSection.get("slots")); + if (slots.isEmpty()) { + return; + } + + boolean editor = viewer.hasPermission("perplayerkit.editkitroom") || viewer.isOp(); + String variant = editor ? "editor" : "viewer"; + applyVariant(menu.getSlot(slots.get(0)), viewer, elementSection, variant, context, skipCloseSave); + } + + private void renderItemData(Menu menu, Player viewer, List slots, ItemStack[] data, boolean editable) { + for (int i = 0; i < slots.size(); i++) { + Slot slot = menu.getSlot(slots.get(i)); + ItemStack item = data != null && i < data.length ? cloneItem(data[i]) : null; + slot.setItem(item); + if (editable) { + allowModification(slot); + } + } + } + + private void applyVariant(Slot slot, Player viewer, ConfigurationSection elementSection, String variantName, GuiContext context, AtomicBoolean skipCloseSave) { + ConfigurationSection variantSection = getVariantSection(elementSection, variantName); + if (variantSection == null) { + return; + } + + ConfigurationSection itemSection = variantSection.getConfigurationSection("item"); + if (itemSection != null) { + ItemStack item = buildItem(itemSection, viewer, context); + if (item != null) { + slot.setItem(item); + } + } + + boolean editable = variantSection.getBoolean("editable", elementSection.getBoolean("editable", false)); + if (editable) { + allowModification(slot); + } + + bindActions(slot, getActionSection(elementSection, variantSection), context, skipCloseSave); + } + + private ConfigurationSection getActionSection(ConfigurationSection elementSection, ConfigurationSection variantSection) { + ConfigurationSection actionsSection = variantSection.getConfigurationSection("actions"); + if (actionsSection != null) { + return actionsSection; + } + return elementSection.getConfigurationSection("actions"); + } + + private ConfigurationSection getVariantSection(ConfigurationSection elementSection, String variantName) { + ConfigurationSection variantsSection = elementSection.getConfigurationSection("variants"); + if (variantsSection == null) { + return elementSection; + } + + if (variantName != null) { + ConfigurationSection variantSection = variantsSection.getConfigurationSection(variantName); + if (variantSection != null) { + return variantSection; + } + } + + return variantsSection.getConfigurationSection("default"); + } + + private void bindActions(Slot slot, ConfigurationSection actionsSection, GuiContext context, AtomicBoolean skipCloseSave) { + if (actionsSection == null) { + return; + } + + slot.setClickHandler((player, info) -> { + List> actions = resolveActions(actionsSection, info.getClickType()); + if (actions.isEmpty()) { + return; + } + + SoundManager.playClick(player); + for (Map action : actions) { + if (executeAction(player, info.getClickedMenu(), context, action, skipCloseSave)) { + if (readBoolean(action, "stop", false)) { + break; + } + } + } + }); + } + + private boolean executeAction(Player player, Menu menu, GuiContext context, Map action, AtomicBoolean skipCloseSave) { + String type = readString(action, "type"); + if (type == null || type.isEmpty()) { + return false; + } + + String permission = readString(action, "permission"); + if (permission != null && !permission.isEmpty() && !player.hasPermission(permission)) { + return false; + } + + boolean success; + switch (type.toLowerCase(Locale.ROOT)) { + case "open-gui": + success = executeOpenGuiAction(player, action, context); + return success; + case "load-player-kit": + success = KitManager.get().loadKit(player, resolveInt(action, "slot", context, "slot", 1)); + handleConfiguredMessages(player, action, context, success); + maybeCloseMenu(player, menu, action, success, skipCloseSave); + return success; + case "load-enderchest": + success = KitManager.get().loadEnderchest(player, resolveInt(action, "slot", context, "slot", 1)); + handleConfiguredMessages(player, action, context, success); + maybeCloseMenu(player, menu, action, success, skipCloseSave); + return success; + case "load-public-kit": + success = KitManager.get().loadPublicKit(player, resolveString(action, "public-kit-id", context, "public_kit_id")); + handleConfiguredMessages(player, action, context, success); + maybeCloseMenu(player, menu, action, success, skipCloseSave); + return success; + case "close": + menu.close(player); + SoundManager.playCloseGui(player); + return true; + case "clear-editor-range": + clearMenuSlots(menu, player, parseSlots(action.get("slots"))); + return true; + case "import-player-inventory": + importContentsIntoMenu(menu, player, getPlayerInventoryContents(player), parseSlots(action.get("slots"))); + return true; + case "import-player-enderchest": + importContentsIntoMenu(menu, player, getPlayerEnderchestContents(player), parseSlots(action.get("slots"))); + return true; + case "clear-player-inventory": + player.getInventory().clear(); + player.sendMessage(ChatColor.GREEN + "Inventory cleared"); + SoundManager.playSuccess(player); + return true; + case "repair-player-items": + BroadcastManager.get().broadcastPlayerRepaired(player); + PlayerUtil.repairAll(player); + player.updateInventory(); + SoundManager.playSuccess(player); + return true; + case "delete-player-kit": + success = deletePlayerKit(player, action, context); + maybeCloseMenu(player, menu, action, success, skipCloseSave); + return success; + case "delete-player-enderchest": + success = deletePlayerEnderchest(player, action, context); + maybeCloseMenu(player, menu, action, success, skipCloseSave); + return success; + case "save-kit-room-page": + success = saveKitRoomPage(player, menu, context); + handleConfiguredMessages(player, action, context, success); + return success; + case "broadcast-kit-room-opened": + BroadcastManager.get().broadcastPlayerOpenedKitRoom(player); + return true; + default: + plugin.getLogger().warning("Unknown GUI action type '" + type + "'"); + return false; + } + } + + private boolean executeOpenGuiAction(Player player, Map action, GuiContext context) { + String guiId = readString(action, "gui"); + if (guiId == null || guiId.isEmpty()) { + return false; + } + + GuiContext nextContext = buildActionContext(player, context, action.get("context")); + Menu nextMenu = openConfiguredGui(guiId, player, nextContext); + return nextMenu != null; + } + + private boolean deletePlayerKit(Player player, Map action, GuiContext context) { + UUID targetUuid = resolveTargetUuid(player, context); + int slot = resolveInt(action, "slot", context, "slot", 1); + boolean success = KitManager.get().deleteKit(targetUuid, slot); + + if (success) { + SoundManager.playSuccess(player); + } else { + SoundManager.playFailure(player); + } + + handleConfiguredMessages(player, action, context, success); + return success; + } + + private boolean deletePlayerEnderchest(Player player, Map action, GuiContext context) { + UUID targetUuid = resolveTargetUuid(player, context); + int slot = resolveInt(action, "slot", context, "slot", 1); + boolean success = KitManager.get().deleteEnderchest(targetUuid, slot); + + if (success) { + SoundManager.playSuccess(player); + } else { + SoundManager.playFailure(player); + } + + handleConfiguredMessages(player, action, context, success); + return success; + } + + private boolean saveKitRoomPage(Player player, Menu menu, GuiContext context) { + int page = getRequiredInt(context, "page", 0); + List dataSlots = getComponentSlots("kit-room", "kit-room-data"); + if (dataSlots.isEmpty()) { + return false; + } + + ItemStack[] kitRoomItems = readMenuItems(menu, player, dataSlots); + KitRoomDataManager.get().setKitRoom(page, kitRoomItems); + KitRoomDataManager.get().saveToDBAsync(); + SoundManager.playSuccess(player); + return true; + } + + private void maybeCloseMenu(Player player, Menu menu, Map action, boolean success, AtomicBoolean skipCloseSave) { + if (!success) { + return; + } + + if (readBoolean(action, "skip-close-save", false)) { + skipCloseSave.set(true); + } + + if (readBoolean(action, "close", false)) { + menu.close(player); + SoundManager.playCloseGui(player); + } + } + + private void handleConfiguredMessages(Player player, Map action, GuiContext context, boolean success) { + String message = readString(action, success ? "success-message" : "failure-message"); + if (message == null || message.isEmpty()) { + return; + } + player.sendMessage(resolveText(message, player, context)); + } + + private void clearMenuSlots(Menu menu, Player player, List slots) { + for (int slotIndex : slots) { + menu.getSlot(slotIndex).setRawItem(player, null); + } + } + + private void importContentsIntoMenu(Menu menu, Player player, ItemStack[] source, List slots) { + for (int i = 0; i < slots.size(); i++) { + ItemStack item = i < source.length ? source[i] : null; + menu.getSlot(slots.get(i)).setRawItem(player, cloneItem(item)); + } + } + + private ItemStack[] getPlayerInventoryContents(Player player) { + ItemStack[] contents = player.getInventory().getContents(); + if (!plugin.getConfig().getBoolean("anti-exploit.import-filter", false)) { + return contents; + } + return ItemFilter.get().filterItemStack(contents); + } + + private ItemStack[] getPlayerEnderchestContents(Player player) { + ItemStack[] contents = player.getEnderChest().getContents(); + if (!plugin.getConfig().getBoolean("anti-exploit.import-filter", false)) { + return contents; + } + return ItemFilter.get().filterItemStack(contents); + } + + private void applyCloseHandler(String guiId, Menu menu, GuiContext context, AtomicBoolean skipCloseSave) { + switch (guiId) { + case "player-kit-editor": + menu.setCloseHandler((player, closedMenu) -> savePlayerKitEditor(player, closedMenu, context, skipCloseSave)); + return; + case "public-kit-editor": + menu.setCloseHandler((player, closedMenu) -> savePublicKitEditor(player, closedMenu, context, skipCloseSave)); + return; + case "enderchest-editor": + menu.setCloseHandler((player, closedMenu) -> saveEnderchestEditor(player, closedMenu, context, skipCloseSave)); + return; + case "inspect-kit": + menu.setCloseHandler((player, closedMenu) -> saveInspectKitEditor(player, closedMenu, context, skipCloseSave)); + return; + case "inspect-enderchest": + menu.setCloseHandler((player, closedMenu) -> saveInspectEnderchestEditor(player, closedMenu, context, skipCloseSave)); + return; + default: + } + } + + private void savePlayerKitEditor(Player player, Menu menu, GuiContext context, AtomicBoolean skipCloseSave) { + if (skipCloseSave.get()) { + return; + } + + int slot = getRequiredInt(context, "slot", 1); + ItemStack[] kit = readMenuItems(menu, player, getComponentSlots("player-kit-editor", "kit-data")); + KitManager.get().savekit(player.getUniqueId(), slot, kit); + } + + private void savePublicKitEditor(Player player, Menu menu, GuiContext context, AtomicBoolean skipCloseSave) { + if (skipCloseSave.get()) { + return; + } + + String publicKitId = context.getString("public_kit_id"); + if (publicKitId == null || publicKitId.isEmpty()) { + return; + } + + ItemStack[] kit = readMenuItems(menu, player, getComponentSlots("public-kit-editor", "kit-data")); + KitManager.get().savePublicKit(player, publicKitId, kit); + } + + private void saveEnderchestEditor(Player player, Menu menu, GuiContext context, AtomicBoolean skipCloseSave) { + if (skipCloseSave.get()) { + return; + } + + int slot = getRequiredInt(context, "slot", 1); + ItemStack[] kit = readMenuItems(menu, player, getComponentSlots("enderchest-editor", "enderchest-data")); + KitManager.get().saveEC(player.getUniqueId(), slot, kit); + } + + private void saveInspectKitEditor(Player player, Menu menu, GuiContext context, AtomicBoolean skipCloseSave) { + if (skipCloseSave.get() || !player.hasPermission("perplayerkit.admin")) { + return; + } + + UUID targetUuid = context.getUuid("target_uuid"); + if (targetUuid == null) { + return; + } + + int slot = getRequiredInt(context, "slot", 1); + String targetName = context.getString("target_name"); + ItemStack[] kit = readMenuItems(menu, player, getComponentSlots("inspect-kit", "kit-data")); + + if (KitManager.get().savekit(targetUuid, slot, kit, true)) { + player.sendMessage(ChatColor.GREEN + "Kit " + slot + " updated for player " + targetName + "!"); + } else { + player.sendMessage(ChatColor.RED + "Failed to update kit for player " + targetName + "!"); + } + } + + private void saveInspectEnderchestEditor(Player player, Menu menu, GuiContext context, AtomicBoolean skipCloseSave) { + if (skipCloseSave.get() || !player.hasPermission("perplayerkit.admin")) { + return; + } + + UUID targetUuid = context.getUuid("target_uuid"); + if (targetUuid == null) { + return; + } + + int slot = getRequiredInt(context, "slot", 1); + String targetName = context.getString("target_name"); + ItemStack[] kit = readMenuItems(menu, player, getComponentSlots("inspect-enderchest", "enderchest-data")); + + if (KitManager.get().saveECSilent(targetUuid, slot, kit)) { + player.sendMessage(ChatColor.GREEN + "Enderchest " + slot + " updated for player " + targetName + "!"); + } else { + player.sendMessage(ChatColor.RED + "Failed to update enderchest for player " + targetName + "!"); + } + } + + private ItemStack[] readMenuItems(Menu menu, Player player, List slots) { + ItemStack[] contents = new ItemStack[slots.size()]; + for (int i = 0; i < slots.size(); i++) { + contents[i] = cloneItem(menu.getSlot(slots.get(i)).getRawItem(player)); + } + return contents; + } + + private List getComponentSlots(String guiId, String componentName) { + ConfigurationSection guiSection = guiConfigManager.getGuiSection(guiId); + if (guiSection == null) { + return Collections.emptyList(); + } + + for (ConfigurationSection elementSection : getOrderedElementSections(guiSection)) { + if (!"component".equalsIgnoreCase(elementSection.getString("type", "")) + || !componentName.equalsIgnoreCase(elementSection.getString("component", ""))) { + continue; + } + return parseSlots(elementSection.get("slots")); + } + + return Collections.emptyList(); + } + + private List getOrderedElementSections(ConfigurationSection guiSection) { + ConfigurationSection elementsSection = guiSection.getConfigurationSection("elements"); + if (elementsSection == null) { + return Collections.emptyList(); + } + + List sections = new ArrayList<>(); + for (String key : elementsSection.getKeys(false)) { + ConfigurationSection section = elementsSection.getConfigurationSection(key); + if (section != null) { + sections.add(section); + } + } + sections.sort((left, right) -> Integer.compare(left.getInt("order", 0), right.getInt("order", 0))); + return sections; + } + + private boolean isVisibleToViewer(ConfigurationSection section, Player viewer) { + String permission = section.getString("permission"); + if (permission != null && !permission.isEmpty() && !viewer.hasPermission(permission)) { + return false; + } + + String excludedPermission = section.getString("exclude-permission"); + return excludedPermission == null || excludedPermission.isEmpty() || !viewer.hasPermission(excludedPermission); + } + + private void allowModification(Slot slot) { + slot.setClickOptions(ClickOptions.ALLOW_ALL); + } + + private ItemStack[] resolveKitData(Player viewer, GuiContext context) { + String publicKitId = context.getString("public_kit_id"); + if (publicKitId != null && !publicKitId.isEmpty()) { + return cloneItemArray(KitManager.get().getItemStackArrayById(IDUtil.getPublicKitId(publicKitId))); + } + + UUID ownerUuid = resolveTargetUuid(viewer, context); + int slot = getRequiredInt(context, "slot", 1); + return cloneItemArray(KitManager.get().getItemStackArrayById(IDUtil.getPlayerKitId(ownerUuid, slot))); + } + + private ItemStack[] resolveEnderchestData(Player viewer, GuiContext context) { + UUID ownerUuid = resolveTargetUuid(viewer, context); + int slot = getRequiredInt(context, "slot", 1); + return cloneItemArray(KitManager.get().getItemStackArrayById(IDUtil.getECId(ownerUuid, slot))); + } + + private ItemStack[] resolveKitRoomData(GuiContext context) { + int page = getRequiredInt(context, "page", 0); + return cloneItemArray(KitRoomDataManager.get().getKitRoomPage(page)); + } + + private UUID resolveTargetUuid(Player viewer, GuiContext context) { + UUID targetUuid = context.getUuid("target_uuid"); + return targetUuid != null ? targetUuid : viewer.getUniqueId(); + } + + private GuiContext enrichPublicKitContext(GuiContext context, String publicKitId) { + PublicKit publicKit = KitManager.get().getPublicKitList().stream() + .filter(entry -> entry.id.equals(publicKitId)) + .findFirst() + .orElse(null); + + GuiContext enriched = context.with("public_kit_id", publicKitId); + if (publicKit != null) { + enriched = enriched + .with("public_kit_name", publicKit.name) + .with("public_kit_icon", publicKit.icon); + } + return enriched; + } + + private List parseSlots(Object rawValue) { + if (rawValue == null) { + return Collections.emptyList(); + } + + LinkedHashSet slots = new LinkedHashSet<>(); + if (rawValue instanceof Number number) { + slots.add(number.intValue()); + } else if (rawValue instanceof String stringValue) { + parseSlotString(stringValue, slots); + } else if (rawValue instanceof List list) { + for (Object entry : list) { + if (entry instanceof Number number) { + slots.add(number.intValue()); + } else if (entry instanceof String stringValue) { + parseSlotString(stringValue, slots); + } + } + } + return new ArrayList<>(slots); + } + + private void parseSlotString(String slotString, LinkedHashSet slots) { + for (String part : slotString.split(",")) { + String trimmed = part.trim(); + if (trimmed.isEmpty()) { + continue; + } + + if (trimmed.contains("-")) { + String[] bounds = trimmed.split("-", 2); + try { + int start = Integer.parseInt(bounds[0].trim()); + int end = Integer.parseInt(bounds[1].trim()); + if (start <= end) { + for (int value = start; value <= end; value++) { + slots.add(value); + } + } else { + for (int value = start; value >= end; value--) { + slots.add(value); + } + } + } catch (NumberFormatException ignored) { + plugin.getLogger().warning("Invalid slot range '" + trimmed + "' in guis.yml"); + } + continue; + } + + try { + slots.add(Integer.parseInt(trimmed)); + } catch (NumberFormatException ignored) { + plugin.getLogger().warning("Invalid slot '" + trimmed + "' in guis.yml"); + } + } + } + + private ItemStack buildItem(ConfigurationSection itemSection, Player viewer, GuiContext context) { + if (itemSection == null) { + return null; + } + + Material material = resolveMaterial(itemSection.getString("material"), viewer, context); + if (material == null) { + return null; + } + + int amount = Math.max(1, itemSection.getInt("amount", 1)); + ItemStack item = new ItemStack(material, amount); + ItemMeta meta = item.getItemMeta(); + + if (meta != null) { + String name = itemSection.getString("name"); + if (name != null) { + meta.setDisplayName(resolveText(name, viewer, context)); + } + + List loreLines = itemSection.getStringList("lore"); + if (!loreLines.isEmpty()) { + List lore = new ArrayList<>(loreLines.size()); + for (String loreLine : loreLines) { + lore.add(resolveText(loreLine, viewer, context)); + } + meta.setLore(lore); + } + + if (itemSection.getBoolean("glow", false)) { + meta.addEnchant(Enchantment.MENDING, 1, true); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + } + + if (itemSection.getBoolean("hide-flags", false)) { + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS, ItemFlag.HIDE_POTION_EFFECTS, ItemFlag.HIDE_ATTRIBUTES, + ItemFlag.HIDE_UNBREAKABLE, ItemFlag.HIDE_DESTROYS, ItemFlag.HIDE_PLACED_ON, ItemFlag.HIDE_DYE); + } + + item.setItemMeta(meta); + } + + return item; + } + + private Material resolveMaterial(String materialName, Player viewer, GuiContext context) { + if (materialName == null || materialName.isEmpty()) { + return null; + } + + String resolvedName = resolvePlainValue(materialName, viewer, context); + if ("@glass".equalsIgnoreCase(resolvedName)) { + return StyleManager.get().getGlassMaterial(); + } + + if (resolvedName.startsWith("@")) { + Object dynamicValue = context.get(resolvedName.substring(1)); + if (dynamicValue instanceof Material material) { + return material; + } + if (dynamicValue != null) { + resolvedName = String.valueOf(dynamicValue); + } + } + + return resolveMaterialName(resolvedName, null); + } + + private Material resolveMaterialName(String materialName, Material fallback) { + try { + return Material.valueOf(materialName.toUpperCase(Locale.ROOT)); + } catch (IllegalArgumentException ignored) { + return fallback; + } + } + + private String resolveText(String value, Player viewer, GuiContext context) { + if (value == null) { + return null; + } + + String resolved = resolvePlainValue(value, viewer, context); + if (Bukkit.getPluginManager().getPlugin("PlaceholderAPI") != null) { + resolved = PlaceholderAPI.setPlaceholders(viewer, resolved); + } + return StyleManager.convertMiniMessage(resolved); + } + + private String resolvePlainValue(String value, Player viewer, GuiContext context) { + Matcher matcher = PLACEHOLDER_PATTERN.matcher(value); + StringBuffer buffer = new StringBuffer(); + + while (matcher.find()) { + String replacement = getPlaceholderValue(matcher.group(1), viewer, context); + matcher.appendReplacement(buffer, Matcher.quoteReplacement(replacement)); + } + + matcher.appendTail(buffer); + return buffer.toString(); + } + + private String getPlaceholderValue(String placeholder, Player viewer, GuiContext context) { + Object contextValue = context.get(placeholder); + if (contextValue != null) { + return String.valueOf(contextValue); + } + + switch (placeholder) { + case "viewer_name": + return viewer.getName(); + case "viewer_display_name": + return viewer.getDisplayName(); + case "viewer_uuid": + return viewer.getUniqueId().toString(); + case "primary_color": + return StyleManager.get().getPrimaryColor(); + case "glass_material": + return StyleManager.get().getGlassMaterial().name(); + default: + return "%" + placeholder + "%"; + } + } + + private GuiContext buildActionContext(Player player, GuiContext baseContext, Object rawContext) { + if (!(rawContext instanceof Map rawContextMap)) { + return baseContext; + } + + GuiContext nextContext = baseContext; + for (Map.Entry entry : rawContextMap.entrySet()) { + if (entry.getKey() == null || entry.getValue() == null) { + continue; + } + + String key = String.valueOf(entry.getKey()); + Object value = resolveContextValue(player, baseContext, entry.getValue()); + if (value != null) { + nextContext = nextContext.with(key, value); + } + } + return nextContext; + } + + private Object resolveContextValue(Player player, GuiContext context, Object rawValue) { + if (!(rawValue instanceof String stringValue)) { + return rawValue; + } + + if (stringValue.startsWith("%") && stringValue.endsWith("%") && stringValue.indexOf('%', 1) == stringValue.length() - 1) { + String placeholder = stringValue.substring(1, stringValue.length() - 1); + Object existing = context.get(placeholder); + if (existing != null) { + return existing; + } + } + + return resolvePlainValue(stringValue, player, context); + } + + private List> resolveActions(ConfigurationSection actionsSection, ClickType clickType) { + List candidates = new ArrayList<>(); + candidates.add(clickType.name().toLowerCase(Locale.ROOT)); + if (clickType.isShiftClick()) { + candidates.add("shift"); + } + if (clickType.isLeftClick()) { + candidates.add("left"); + } else if (clickType.isRightClick()) { + candidates.add("right"); + } else if (clickType == ClickType.MIDDLE) { + candidates.add("middle"); + } + candidates.add("any"); + + for (String candidate : candidates) { + List> actions = readActionList(actionsSection, candidate); + if (!actions.isEmpty()) { + return actions; + } + } + + return Collections.emptyList(); + } + + private List> readActionList(ConfigurationSection actionsSection, String path) { + List rawActions = actionsSection.getList(path); + if (rawActions == null || rawActions.isEmpty()) { + return Collections.emptyList(); + } + + List> actions = new ArrayList<>(); + for (Object rawAction : rawActions) { + if (rawAction instanceof Map map) { + actions.add(map); + } + } + return actions; + } + + private String readString(Map map, String key) { + Object value = map.get(key); + return value == null ? null : String.valueOf(value); + } + + private boolean readBoolean(Map map, String key, boolean defaultValue) { + Object value = map.get(key); + if (value instanceof Boolean bool) { + return bool; + } + if (value instanceof String stringValue) { + return Boolean.parseBoolean(stringValue); + } + return defaultValue; + } + + private String resolveString(Map action, String key, GuiContext context, String fallbackContextKey) { + String rawValue = readString(action, key); + if (rawValue != null) { + if (rawValue.startsWith("%") && rawValue.endsWith("%") && rawValue.indexOf('%', 1) == rawValue.length() - 1) { + String placeholder = rawValue.substring(1, rawValue.length() - 1); + Object contextValue = context.get(placeholder); + if (contextValue != null) { + return String.valueOf(contextValue); + } + } + return rawValue; + } + return context.getString(fallbackContextKey); + } + + private int resolveInt(Map action, String key, GuiContext context, String fallbackContextKey, int defaultValue) { + Object rawValue = action.get(key); + if (rawValue instanceof Number number) { + return number.intValue(); + } + if (rawValue instanceof String stringValue) { + try { + return Integer.parseInt(stringValue); + } catch (NumberFormatException ignored) { + return defaultValue; + } + } + + Integer contextValue = context.getInt(fallbackContextKey); + return contextValue != null ? contextValue : defaultValue; + } + + private int getRequiredInt(GuiContext context, String key, int defaultValue) { + Integer value = context.getInt(key); + return value != null ? value : defaultValue; + } + + private ItemStack cloneItem(ItemStack item) { + return item == null ? null : item.clone(); + } + + private ItemStack[] cloneItemArray(ItemStack[] items) { + if (items == null) { + return null; + } + + ItemStack[] clone = new ItemStack[items.length]; + for (int i = 0; i < items.length; i++) { + clone[i] = cloneItem(items[i]); + } + return clone; + } + + private String getPlayerName(UUID uuid) { + Player onlinePlayer = Bukkit.getPlayer(uuid); + if (onlinePlayer != null) { + return onlinePlayer.getName(); + } + + OfflinePlayer offlinePlayer = Bukkit.getOfflinePlayer(uuid); + return offlinePlayer.getName() != null ? offlinePlayer.getName() : uuid.toString(); + } +} diff --git a/src/main/java/dev/noah/perplayerkit/gui/configurable/GuiConfigManager.java b/src/main/java/dev/noah/perplayerkit/gui/configurable/GuiConfigManager.java new file mode 100644 index 0000000..dd301a5 --- /dev/null +++ b/src/main/java/dev/noah/perplayerkit/gui/configurable/GuiConfigManager.java @@ -0,0 +1,31 @@ +package dev.noah.perplayerkit.gui.configurable; + +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.plugin.Plugin; + +import java.io.File; + +public class GuiConfigManager { + private final Plugin plugin; + private final File guiConfigFile; + private FileConfiguration guiConfiguration; + + public GuiConfigManager(Plugin plugin) { + this.plugin = plugin; + this.guiConfigFile = new File(plugin.getDataFolder(), "guis.yml"); + load(); + } + + public final void load() { + if (!guiConfigFile.exists()) { + plugin.saveResource("guis.yml", false); + } + guiConfiguration = YamlConfiguration.loadConfiguration(guiConfigFile); + } + + public ConfigurationSection getGuiSection(String guiId) { + return guiConfiguration.getConfigurationSection("guis." + guiId); + } +} diff --git a/src/main/java/dev/noah/perplayerkit/gui/configurable/GuiContext.java b/src/main/java/dev/noah/perplayerkit/gui/configurable/GuiContext.java new file mode 100644 index 0000000..b0c6431 --- /dev/null +++ b/src/main/java/dev/noah/perplayerkit/gui/configurable/GuiContext.java @@ -0,0 +1,90 @@ +package dev.noah.perplayerkit.gui.configurable; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.UUID; + +public final class GuiContext { + private static final GuiContext EMPTY = new GuiContext(Collections.emptyMap()); + + private final Map values; + + private GuiContext(Map values) { + this.values = Collections.unmodifiableMap(values); + } + + public static GuiContext empty() { + return EMPTY; + } + + public GuiContext with(String key, Object value) { + if (key == null || value == null) { + return this; + } + + Map updated = new LinkedHashMap<>(values); + updated.put(key, value); + return new GuiContext(updated); + } + + public GuiContext withAll(Map additionalValues) { + if (additionalValues == null || additionalValues.isEmpty()) { + return this; + } + + Map updated = new LinkedHashMap<>(values); + additionalValues.forEach((key, value) -> { + if (key != null && value != null) { + updated.put(key, value); + } + }); + return new GuiContext(updated); + } + + public Object get(String key) { + return values.get(key); + } + + public String getString(String key) { + Object value = values.get(key); + return value == null ? null : String.valueOf(value); + } + + public Integer getInt(String key) { + Object value = values.get(key); + if (value instanceof Integer integer) { + return integer; + } + if (value instanceof Number number) { + return number.intValue(); + } + if (value instanceof String stringValue) { + try { + return Integer.parseInt(stringValue); + } catch (NumberFormatException ignored) { + return null; + } + } + return null; + } + + public UUID getUuid(String key) { + Object value = values.get(key); + if (value instanceof UUID uuid) { + return uuid; + } + if (value instanceof String stringValue) { + try { + return UUID.fromString(stringValue); + } catch (IllegalArgumentException ignored) { + return null; + } + } + return null; + } + + public Map values() { + return values; + } +} diff --git a/src/main/resources/guis.yml b/src/main/resources/guis.yml new file mode 100644 index 0000000..57e9aa2 --- /dev/null +++ b/src/main/resources/guis.yml @@ -0,0 +1,822 @@ +guis: + main-menu: + rows: 6 + title: "%primary_color%%viewer_name%'s Kits" + elements: + fill: + order: 0 + type: fill + slots: "0-53" + item: + material: "@glass" + name: " " + player-kits: + order: 10 + type: component + component: player-kit-selector + slots: "9-17" + start-index: 1 + variants: + default: + item: + material: CHEST + name: "Kit %slot%" + lore: + - "● Left click to load kit" + - "● Right click to edit kit" + actions: + left: + - type: load-player-kit + close: true + right: + - type: open-gui + gui: player-kit-editor + context: + slot: "%slot%" + enderchests: + order: 20 + type: component + component: enderchest-selector + slots: "18-26" + start-index: 1 + variants: + exists: + item: + material: ENDER_CHEST + name: "Enderchest %slot%" + lore: + - "● Left click to load kit" + - "● Right click to edit kit" + actions: + left: + - type: load-enderchest + close: true + right: + - type: open-gui + gui: enderchest-editor + context: + slot: "%slot%" + missing: + item: + material: ENDER_EYE + name: "Enderchest %slot%" + lore: + - "● Click to create" + actions: + any: + - type: open-gui + gui: enderchest-editor + context: + slot: "%slot%" + kit-status: + order: 30 + type: component + component: kit-status-selector + slots: "27-35" + start-index: 1 + variants: + exists: + item: + material: KNOWLEDGE_BOOK + name: "KIT EXISTS" + lore: + - "● Click to edit" + actions: + any: + - type: open-gui + gui: player-kit-editor + context: + slot: "%slot%" + missing: + item: + material: BOOK + name: "KIT NOT FOUND" + lore: + - "● Click to create" + actions: + any: + - type: open-gui + gui: player-kit-editor + context: + slot: "%slot%" + kit-room: + order: 40 + type: static + slots: "37" + item: + material: NETHER_STAR + name: "KIT ROOM" + actions: + any: + - type: open-gui + gui: kit-room + context: + page: "0" + page_display: "1" + - type: broadcast-kit-room-opened + public-kits: + order: 41 + type: static + slots: "38" + item: + material: BOOKSHELF + name: "PREMADE KITS" + actions: + any: + - type: open-gui + gui: public-kit-menu + info: + order: 42 + type: static + slots: "39" + item: + material: OAK_SIGN + name: "INFO" + lore: + - "● Click a kit slot to load your kit" + - "● Right click or click the book to edit" + - "● Share kits with /sharekit " + clear-inventory: + order: 43 + type: static + slots: "41" + item: + material: REDSTONE_BLOCK + name: "CLEAR INVENTORY" + lore: + - "● Shift click" + actions: + shift: + - type: clear-player-inventory + share-info: + order: 44 + type: static + slots: "42" + item: + material: COMPASS + name: "SHARE KITS" + lore: + - "● /sharekit " + repair: + order: 45 + type: static + slots: "43" + item: + material: EXPERIENCE_BOTTLE + name: "REPAIR ITEMS" + actions: + any: + - type: repair-player-items + + player-kit-editor: + rows: 6 + title: "%primary_color%Kit: %slot%" + elements: + fill: + order: 0 + type: fill + slots: "0-53" + item: + material: "@glass" + name: " " + data: + order: 10 + type: component + component: kit-data + slots: "0-40" + editable: true + boots: + order: 20 + type: static + slots: "45" + item: + material: CHAINMAIL_BOOTS + name: "BOOTS" + leggings: + order: 21 + type: static + slots: "46" + item: + material: CHAINMAIL_LEGGINGS + name: "LEGGINGS" + chestplate: + order: 22 + type: static + slots: "47" + item: + material: CHAINMAIL_CHESTPLATE + name: "CHESTPLATE" + helmet: + order: 23 + type: static + slots: "48" + item: + material: CHAINMAIL_HELMET + name: "HELMET" + offhand: + order: 24 + type: static + slots: "49" + item: + material: SHIELD + name: "OFFHAND" + import: + order: 30 + type: static + slots: "51" + item: + material: CHEST + name: "IMPORT" + lore: + - "● Import from inventory" + actions: + any: + - type: import-player-inventory + slots: "0-40" + clear: + order: 31 + type: static + slots: "52" + item: + material: BARRIER + name: "CLEAR KIT" + lore: + - "● Shift click to clear" + actions: + shift: + - type: clear-editor-range + slots: "0-40" + back: + order: 32 + type: static + slots: "53" + item: + material: OAK_DOOR + name: "BACK" + actions: + any: + - type: open-gui + gui: main-menu + + public-kit-editor: + rows: 6 + title: "%primary_color%Public Kit: %public_kit_id%" + elements: + fill: + order: 0 + type: fill + slots: "0-53" + item: + material: "@glass" + name: " " + data: + order: 10 + type: component + component: kit-data + slots: "0-40" + editable: true + boots: + order: 20 + type: static + slots: "45" + item: + material: CHAINMAIL_BOOTS + name: "BOOTS" + leggings: + order: 21 + type: static + slots: "46" + item: + material: CHAINMAIL_LEGGINGS + name: "LEGGINGS" + chestplate: + order: 22 + type: static + slots: "47" + item: + material: CHAINMAIL_CHESTPLATE + name: "CHESTPLATE" + helmet: + order: 23 + type: static + slots: "48" + item: + material: CHAINMAIL_HELMET + name: "HELMET" + offhand: + order: 24 + type: static + slots: "49" + item: + material: SHIELD + name: "OFFHAND" + import: + order: 30 + type: static + slots: "51" + item: + material: CHEST + name: "IMPORT" + lore: + - "● Import from inventory" + actions: + any: + - type: import-player-inventory + slots: "0-40" + clear: + order: 31 + type: static + slots: "52" + item: + material: BARRIER + name: "CLEAR KIT" + lore: + - "● Shift click to clear" + actions: + shift: + - type: clear-editor-range + slots: "0-40" + back: + order: 32 + type: static + slots: "53" + item: + material: OAK_DOOR + name: "BACK" + actions: + any: + - type: open-gui + gui: main-menu + + enderchest-editor: + rows: 6 + title: "%primary_color%Enderchest: %slot%" + elements: + fill: + order: 0 + type: fill + slots: "0-53" + item: + material: "@glass" + name: " " + data: + order: 10 + type: component + component: enderchest-data + slots: "9-35" + editable: true + import: + order: 30 + type: static + slots: "51" + item: + material: ENDER_CHEST + name: "IMPORT" + lore: + - "● Import from enderchest" + actions: + any: + - type: import-player-enderchest + slots: "9-35" + clear: + order: 31 + type: static + slots: "52" + item: + material: BARRIER + name: "CLEAR KIT" + lore: + - "● Shift click to clear" + actions: + shift: + - type: clear-editor-range + slots: "9-35" + back: + order: 32 + type: static + slots: "53" + item: + material: OAK_DOOR + name: "BACK" + actions: + any: + - type: open-gui + gui: main-menu + + inspect-kit: + rows: 6 + title: "%primary_color%Inspecting %target_name%'s kit %slot%" + elements: + fill: + order: 0 + type: fill + slots: "0-53" + item: + material: "@glass" + name: " " + data: + order: 10 + type: component + component: kit-data + slots: "0-40" + admin-data: + order: 11 + type: component + component: kit-data + permission: perplayerkit.admin + slots: "0-40" + editable: true + boots: + order: 20 + type: static + slots: "45" + item: + material: CHAINMAIL_BOOTS + name: "BOOTS" + leggings: + order: 21 + type: static + slots: "46" + item: + material: CHAINMAIL_LEGGINGS + name: "LEGGINGS" + chestplate: + order: 22 + type: static + slots: "47" + item: + material: CHAINMAIL_CHESTPLATE + name: "CHESTPLATE" + helmet: + order: 23 + type: static + slots: "48" + item: + material: CHAINMAIL_HELMET + name: "HELMET" + offhand: + order: 24 + type: static + slots: "49" + item: + material: SHIELD + name: "OFFHAND" + delete: + order: 30 + type: static + permission: perplayerkit.admin + slots: "52" + item: + material: BARRIER + name: "CLEAR KIT" + lore: + - "● Shift click to delete kit" + actions: + shift: + - type: delete-player-kit + slot: "%slot%" + close: true + skip-close-save: true + success-message: "Kit %slot% deleted for player!" + close: + order: 31 + type: static + slots: "53" + item: + material: OAK_DOOR + name: "CLOSE" + actions: + any: + - type: close + + inspect-enderchest: + rows: 6 + title: "%primary_color%Inspecting %target_name%'s enderchest %slot%" + elements: + fill: + order: 0 + type: fill + slots: "0-53" + item: + material: "@glass" + name: " " + data: + order: 10 + type: component + component: enderchest-data + slots: "9-35" + admin-data: + order: 11 + type: component + component: enderchest-data + permission: perplayerkit.admin + slots: "9-35" + editable: true + delete: + order: 30 + type: static + permission: perplayerkit.admin + slots: "52" + item: + material: BARRIER + name: "CLEAR ENDERCHEST" + lore: + - "● Shift click to delete enderchest" + actions: + shift: + - type: delete-player-enderchest + slot: "%slot%" + close: true + skip-close-save: true + success-message: "Enderchest %slot% deleted for player!" + close: + order: 31 + type: static + slots: "53" + item: + material: OAK_DOOR + name: "CLOSE" + actions: + any: + - type: close + + public-kit-menu: + rows: 6 + title: "%primary_color%Public Kit Room" + redraw: true + elements: + fill: + order: 0 + type: fill + slots: "0-53" + item: + material: "@glass" + name: " " + coming-soon: + order: 5 + type: static + slots: "18-35" + item: + material: BOOK + name: "MORE KITS COMING SOON" + list: + order: 10 + type: component + component: public-kit-list + slots: "18-35" + variants: + assigned: + item: + material: "@public_kit_icon" + name: "%public_kit_name%" + actions: + left: + - type: load-public-kit + public-kit-id: "%public_kit_id%" + close: true + right: + - type: open-gui + gui: public-kit-viewer + context: + public_kit_id: "%public_kit_id%" + public_kit_name: "%public_kit_name%" + public_kit_icon: "%public_kit_icon%" + unassigned: + item: + material: "@public_kit_icon" + name: "%public_kit_name% [UNASSIGNED]" + lore: + - "● Admins have not yet setup this kit yet" + admin_assigned: + item: + material: "@public_kit_icon" + name: "%public_kit_name%" + lore: + - "● [ADMIN] Shift click to edit" + actions: + shift: + - type: open-gui + gui: public-kit-editor + context: + public_kit_id: "%public_kit_id%" + public_kit_name: "%public_kit_name%" + public_kit_icon: "%public_kit_icon%" + left: + - type: load-public-kit + public-kit-id: "%public_kit_id%" + close: true + right: + - type: open-gui + gui: public-kit-viewer + context: + public_kit_id: "%public_kit_id%" + public_kit_name: "%public_kit_name%" + public_kit_icon: "%public_kit_icon%" + admin_unassigned: + item: + material: "@public_kit_icon" + name: "%public_kit_name% [UNASSIGNED]" + lore: + - "● Admins have not yet setup this kit yet" + - "● [ADMIN] Shift click to edit" + actions: + shift: + - type: open-gui + gui: public-kit-editor + context: + public_kit_id: "%public_kit_id%" + public_kit_name: "%public_kit_name%" + public_kit_icon: "%public_kit_icon%" + back: + order: 20 + type: static + slots: "53" + item: + material: OAK_DOOR + name: "BACK" + actions: + any: + - type: open-gui + gui: main-menu + + public-kit-viewer: + rows: 6 + title: "%primary_color%Viewing Public Kit: %public_kit_id%" + redraw: true + elements: + fill: + order: 0 + type: fill + slots: "0-53" + item: + material: "@glass" + name: " " + data: + order: 10 + type: component + component: kit-data + slots: "0-40" + boots: + order: 20 + type: static + slots: "45" + item: + material: CHAINMAIL_BOOTS + name: "BOOTS" + leggings: + order: 21 + type: static + slots: "46" + item: + material: CHAINMAIL_LEGGINGS + name: "LEGGINGS" + chestplate: + order: 22 + type: static + slots: "47" + item: + material: CHAINMAIL_CHESTPLATE + name: "CHESTPLATE" + helmet: + order: 23 + type: static + slots: "48" + item: + material: CHAINMAIL_HELMET + name: "HELMET" + offhand: + order: 24 + type: static + slots: "49" + item: + material: SHIELD + name: "OFFHAND" + load: + order: 30 + type: static + slots: "52" + item: + material: APPLE + name: "LOAD KIT" + actions: + any: + - type: load-public-kit + public-kit-id: "%public_kit_id%" + close: true + back: + order: 31 + type: static + slots: "53" + item: + material: OAK_DOOR + name: "BACK" + actions: + any: + - type: open-gui + gui: public-kit-menu + + kit-room: + rows: 6 + title: "%primary_color%Kit Room" + redraw: true + elements: + fill: + order: 0 + type: fill + slots: "0-53" + item: + material: "@glass" + name: " " + data: + order: 10 + type: component + component: kit-room-data + slots: "0-44" + editable: true + refill: + order: 20 + type: static + slots: "45" + item: + material: BEACON + name: "REFILL" + actions: + any: + - type: open-gui + gui: kit-room + context: + page: "%page%" + page_display: "%page_display%" + categories: + order: 30 + type: component + component: kit-room-category-buttons + slots: "47-51" + start-page: 0 + variants: + default: + item: + material: "@kitroom_material" + name: "%kitroom_name%" + hide-flags: true + actions: + any: + - type: open-gui + gui: kit-room + context: + page: "%page%" + page_display: "%page_display%" + active: + item: + material: "@kitroom_material" + name: "%kitroom_name%" + hide-flags: true + glow: true + actions: + any: + - type: open-gui + gui: kit-room + context: + page: "%page%" + page_display: "%page_display%" + control: + order: 40 + type: component + component: kit-room-control + slots: "53" + variants: + viewer: + item: + material: OAK_DOOR + name: "BACK" + actions: + any: + - type: open-gui + gui: main-menu + editor: + item: + material: BARRIER + name: "EDIT MENU" + lore: + - "SHIFT RIGHT CLICK TO SAVE" + actions: + shift_right: + - type: save-kit-room-page + success-message: "Saved kitroom page: %page_display%" + + view-only-enderchest: + rows: 5 + title: "%primary_color%View Only Enderchest" + elements: + fill: + order: 0 + type: fill + slots: "0-44" + item: + material: "@glass" + name: " " + data: + order: 10 + type: component + component: player-enderchest-data + slots: "9-35"