diff --git a/src/main/java/com/github/hostadam/Ares.java b/src/main/java/com/github/hostadam/Ares.java index 99ce088..9edfa4b 100644 --- a/src/main/java/com/github/hostadam/Ares.java +++ b/src/main/java/com/github/hostadam/Ares.java @@ -6,8 +6,6 @@ import com.github.hostadam.command.ParameterConverter; import com.github.hostadam.command.handler.CommandHandler; import com.github.hostadam.command.impl.CommandImpl; -import com.github.hostadam.menu.Menu; -import com.github.hostadam.menu.MenuHandler; import org.bukkit.entity.Player; import org.bukkit.plugin.java.JavaPlugin; @@ -19,12 +17,10 @@ public class Ares { private BoardHandler boardHandler; private CommandHandler commandHandler; - private MenuHandler menuHandler; public Ares(JavaPlugin parent) { this.boardHandler = new BoardHandler(parent); this.commandHandler = new CommandHandler(); - this.menuHandler = new MenuHandler(parent); } public void setScoreboardAdapter(BoardAdapter adapter) { @@ -41,11 +37,6 @@ public Board getScoreboard(UUID uniqueId) { return this.boardHandler.getScoreboard(uniqueId); } - /** Menus **/ - public void openMenu(Player player, Menu menu) { - this.menuHandler.openMenu(player, menu); - } - /** Commands **/ public void registerCommand(Object object) { this.commandHandler.register(object); diff --git a/src/main/java/com/github/hostadam/command/AresCommand.java b/src/main/java/com/github/hostadam/command/AresCommand.java index 2e182a4..4eb66dd 100644 --- a/src/main/java/com/github/hostadam/command/AresCommand.java +++ b/src/main/java/com/github/hostadam/command/AresCommand.java @@ -14,5 +14,4 @@ String usage() default ""; String permission() default ""; int requiredArgs() default 0; - CommandTarget target() default CommandTarget.ALL; } diff --git a/src/main/java/com/github/hostadam/command/CommandTarget.java b/src/main/java/com/github/hostadam/command/CommandTarget.java deleted file mode 100644 index 2cc28bc..0000000 --- a/src/main/java/com/github/hostadam/command/CommandTarget.java +++ /dev/null @@ -1,29 +0,0 @@ -package com.github.hostadam.command; - -import org.bukkit.command.CommandSender; -import org.bukkit.command.ConsoleCommandSender; -import org.bukkit.entity.Player; - -public enum CommandTarget { - - PLAYER { - @Override - public boolean testFor(CommandSender sender) { - return sender instanceof Player; - } - }, - CONSOLE { - @Override - public boolean testFor(CommandSender sender) { - return sender instanceof ConsoleCommandSender; - } - }, - ALL { - @Override - public boolean testFor(CommandSender sender) { - return true; - } - }; - - public abstract boolean testFor(CommandSender sender); -} diff --git a/src/main/java/com/github/hostadam/command/handler/CommandHandler.java b/src/main/java/com/github/hostadam/command/handler/CommandHandler.java index 85d7ab3..b2a201e 100644 --- a/src/main/java/com/github/hostadam/command/handler/CommandHandler.java +++ b/src/main/java/com/github/hostadam/command/handler/CommandHandler.java @@ -22,6 +22,7 @@ public class CommandHandler { private CommandMap map; + private final Map, ParameterConverter> parameters; private final Map commands; @@ -62,11 +63,6 @@ public void register(Object object) { CommandImpl parentCommand = this.getCommandByLabel(split[0]); if(parentCommand != null) parentCommand.addSubCommand(data); } else { - List aliases = new ArrayList<>(); - if(command.labels().length > 1) { - aliases.addAll(List.of(Arrays.copyOfRange(command.labels(), 1, command.labels().length))); - } - CommandImpl impl = new CommandImpl(this, data); this.map.register(name, impl); this.commands.put(name, impl); diff --git a/src/main/java/com/github/hostadam/command/impl/CommandData.java b/src/main/java/com/github/hostadam/command/impl/CommandData.java index d94b911..7f3e68e 100644 --- a/src/main/java/com/github/hostadam/command/impl/CommandData.java +++ b/src/main/java/com/github/hostadam/command/impl/CommandData.java @@ -29,21 +29,18 @@ public CommandData(AresCommand command, Method method, Object object) { this.playerOnly = method.getParameters()[0].getType() == Player.class; } - public boolean match(String name) { - for(String string : this.command.labels()) { - if(!string.contains(" ")) continue; - if(string.split(" ")[1].equalsIgnoreCase(name)) { - return true; - } - } - - return false; - } - public void execute(CommandHandler handler, CommandSender sender, String[] args) { int parameters = this.method.getParameterCount(); //2 Object[] objects = new Object[parameters]; //2 + /** + * feed command (args 0 = heal self, args 1 = target) + * onCommand(CommandSender sender, String[] args) + * + * faction create (args 0 = usage, args 1 = name) + * onSubCommand(CommandSender sender, String name) + */ + if(this.playerOnly && !(sender instanceof Player)) { sender.sendMessage("§cOnly players can run this command"); return; @@ -54,43 +51,47 @@ public void execute(CommandHandler handler, CommandSender sender, String[] args) return; } - objects[0] = sender; + objects[0] = (this.playerOnly ? (Player) sender : sender); int argCount = 0; - for(int i = 1; i < parameters; i++) { - Parameter parameter = this.method.getParameters()[i]; - - if(parameter.getType() == String[].class) { - if(i > args.length) { - objects[i] = new String[] {}; + if(parameters > 1) { + for(int i = 1; i < parameters; i++) { + Parameter parameter = this.method.getParameters()[i]; + + if(parameter.getType() == String[].class) { + if(i > args.length) { + argCount++; + objects[i] = new String[] {}; + } else { + String[] arrayCopy = Arrays.copyOfRange(args, i, args.length); + objects[i] = arrayCopy; + argCount += arrayCopy.length; + } } else { - String[] arrayCopy = Arrays.copyOfRange(args, i, args.length); - objects[i] = arrayCopy; - argCount += arrayCopy.length; - } - } else { - if(i - 1 >= args.length) { - sender.sendMessage("§cUsage: /" + this.command.usage()); - return; + if(i - 1 >= args.length) { + sender.sendMessage("§cUsage: /" + this.command.usage()); + return; + } + + argCount++; } - } - argCount++; - ParameterConverter converter = handler.getConverter(parameter.getType()); - if(converter == null) continue; + ParameterConverter converter = handler.getConverter(parameter.getType()); + if(converter == null) continue; + + try { + Object object = converter.convert(args[i - 1].trim()); + if(object == null) { + converter.error(sender, args[i - 1]); + return; + } - try { - Object object = converter.convert(args[i - 1].trim()); - if(object == null) { + objects[i] = object; + } catch(Exception exception) { converter.error(sender, args[i - 1]); return; } - - objects[i] = object; - } catch(Exception exception) { - converter.error(sender, args[i - 1]); - return; } } diff --git a/src/main/java/com/github/hostadam/command/impl/CommandImpl.java b/src/main/java/com/github/hostadam/command/impl/CommandImpl.java index 3b36aef..2b30b92 100644 --- a/src/main/java/com/github/hostadam/command/impl/CommandImpl.java +++ b/src/main/java/com/github/hostadam/command/impl/CommandImpl.java @@ -43,8 +43,11 @@ public void addSubCommand(CommandData data) { public CommandData getSubCommand(String name) { for(CommandData command : this.subcommands) { - if(command.match(name)) { - return command; + for(String string : command.getCommand().labels()) { + if(!string.contains(" ")) continue; + if(string.split(" ")[1].equalsIgnoreCase(name)) { + return command; + } } } diff --git a/src/main/java/com/github/hostadam/menu/Menu.java b/src/main/java/com/github/hostadam/menu/Menu.java index 4a3e420..2a0001a 100644 --- a/src/main/java/com/github/hostadam/menu/Menu.java +++ b/src/main/java/com/github/hostadam/menu/Menu.java @@ -1,123 +1,219 @@ package com.github.hostadam.menu; +import lombok.Getter; +import lombok.Setter; import org.bukkit.Bukkit; -import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryType; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.java.JavaPlugin; import java.util.*; -import java.util.stream.Collectors; public abstract class Menu { - private final Player player; - private String title; + private static final Map PLAYER_MENUS = new HashMap<>(); + + private final JavaPlugin plugin; + @Getter + protected Player player; + @Getter + protected Inventory inventory; + @Setter + private Menu parent; private int size; + private String[] template; + + private Map buttons = new HashMap<>(); + private Map permanentButtons = new HashMap<>(); + private List dynamicalButtons = new ArrayList<>(); + private List airSlots = new ArrayList<>(); - private boolean paginated = true; - private int page = 0, maxPages = 0; - private Inventory inventory; - private final Map buttons = new HashMap<>(); + private int page = 1, maxPages = 1; - public Menu(Player player, String title, int size) { + public Menu(JavaPlugin plugin, Player player, String title, int size) { this.player = player; - this.title = title; + this.plugin = plugin; + this.inventory = Bukkit.createInventory(null, size, title); this.size = size; } - public void init() { - this.build(); + public Menu(JavaPlugin plugin, Player player, InventoryType type, String title) { + this.player = player; + this.plugin = plugin; + this.inventory = Bukkit.createInventory(null, type, title); + this.size = type.getDefaultSize(); + } + + public void setTemplate(String... template) { + if(template.length != this.size / 9) { + throw new UnsupportedOperationException("Template rows must be the same as the size of the inventory."); + } - if(this.paginated) { - Optional highest = this.buttons.keySet().stream() - .max(Integer::compare); - if(highest.isPresent()) { - int highestSlot = highest.get(); - this.maxPages = (int) Math.ceil((double) highestSlot / (this.size - 1)); + for(String row : template) { + if(row.length() != 9) { + throw new UnsupportedOperationException("Each row must be 9 characters long."); } } - } - public void set(int slot, MenuButton button) { - this.buttons.put(slot, button); - button.setSlot(slot); + this.template = template; } public void open() { - this.open(0); - } + if(this.template == null) { + throw new UnsupportedOperationException("No template was found."); + } - public void open(int page) { - this.init(); - this.page = page; - this.inventory = Bukkit.createInventory(null, this.size, this.title); + Menu menu = PLAYER_MENUS.get(player.getUniqueId()); + if(menu != null && !menu.getClass().isInstance(this)) { + this.setParent(menu); + menu.close(); + } - List menuButtons = this.findButtons(this.getStartOfRange(), this.getEndOfRange()); - for(int index = 0; index < menuButtons.size(); index++) { - MenuButton button = this.buttons.get(index); + this.refresh(); + PLAYER_MENUS.put(player.getUniqueId(), this); - ItemStack itemStack = this.inventory.getItem(button.getSlot()); - if(itemStack != null && itemStack.getType() == Material.AIR) { - continue; + if(!Bukkit.isPrimaryThread()) { + Bukkit.getScheduler().runTask(plugin, () -> this.player.openInventory(this.inventory)); + } else { + this.player.openInventory(this.inventory); + } + } + + public void refresh() { + this.airSlots.clear(); + this.buttons.clear(); + this.dynamicalButtons.clear(); + this.permanentButtons.clear(); + this.inventory.clear(); + + this.setup(); + + for(int rowIndex = 0; rowIndex < this.template.length; rowIndex++) { + String row = this.template[rowIndex]; + for(int charIndex = 0; charIndex < row.length(); charIndex++) { + int inventorySlot = (9 * rowIndex) + charIndex; + char c = row.charAt(charIndex); + if(c == ' ') { + this.airSlots.add(inventorySlot); + continue; + } + + if(this.permanentButtons.containsKey(c)) { + MenuItem button = this.permanentButtons.get(c); + this.buttons.put(inventorySlot, button); + } + } + } + + for(int i = 0; i < airSlots.size(); i++) { + int slot = airSlots.get(i); + int buttonIndex = ((this.page - 1) * this.airSlots.size()) + i; + if(buttonIndex >= this.dynamicalButtons.size()) { + break; } - this.inventory.setItem(button.getSlot(), button.build()); + MenuItem button = this.dynamicalButtons.get(buttonIndex); + this.buttons.put(slot, button); + } + + if(!this.dynamicalButtons.isEmpty() && !this.airSlots.isEmpty()) { + this.maxPages = (int) Math.ceil((double) this.dynamicalButtons.size() / (double) airSlots.size()); } - this.player.openInventory(this.inventory); + for(Map.Entry buttons : this.buttons.entrySet()) { + MenuItem button = buttons.getValue(); + ItemStack itemStack = button.getItemStack(); + + if(button.hasFallbackItem()) { + //Only show with proper permission. + if((!button.getPermission().isEmpty() && !player.hasPermission(button.getPermission())) || (button.isPaginated() && button.hasFallbackItem() && ((button.getType() == MenuItem.Type.NEXT_PAGE && !this.hasNextPage()) || (button.getType() == MenuItem.Type.PREVIOUS_PAGE && !this.hasPreviousPage()) || (button.getType() == MenuItem.Type.BACK_TO_MAIN_PAGE && this.parent == null)))) { + itemStack = button.getFallbackItem(); + } + } + + this.inventory.setItem(buttons.getKey(), itemStack); + } } - public int getStartOfRange() { - return this.page * this.size; + public void add(MenuItem item) { + this.dynamicalButtons.add(item); } - public int getEndOfRange() { - //TODO: Subtract the last row if the pages item are there to avoid conflict. - return this.getStartOfRange() + (this.size - 1); + public void set(char c, MenuItem item) { + this.permanentButtons.put(c, item); } - public void nextPage() { - this.open(this.page + 1); + public boolean click(InventoryClickEvent event) { + int slot = event.getRawSlot(); + if(slot == -1) return event.isCancelled(); + + MenuItem button = this.buttons.get(event.getRawSlot()); + if(button != null) { + event.setCancelled(true); + if(button.getClickEvent() != null) button.getClickEvent().accept(event); + if(button.isPaginated()) { + switch(button.getType()) { + case NEXT_PAGE: + this.nextPage(); + break; + case PREVIOUS_PAGE: + this.previousPage(); + break; + case BACK_TO_MAIN_PAGE: + this.mainPage(); + break; + } + } + } + + return event.isCancelled(); } - public void previousPage() { - this.open(this.page - 1); + public void close() { + PLAYER_MENUS.remove(this.player.getUniqueId()); + this.player.closeInventory(); } - public boolean hasPreviousPage() { - return this.page > 0; + public void mainPage() { + this.close(); + this.parent.open(); } public boolean hasNextPage() { - return this.page < (this.maxPages - 1); + return this.page < this.maxPages; } - public boolean hasPages() { - return this.maxPages > 0; + public boolean hasPreviousPage() { + return this.page > 1; } - public List findButtons(int min, int max) { - return this.buttons.entrySet().stream() - .filter(entry -> entry.getKey() >= min && entry.getKey() < max) - .sorted(Map.Entry.comparingByKey()) - .map(Map.Entry::getValue) - .toList(); + public void nextPage() { + if(!this.hasNextPage()) return; + this.page++; + this.refresh(); } - public boolean click(InventoryClickEvent event) { - int slot = event.getRawSlot(); - if(slot == -1) return event.isCancelled(); - MenuButton button = this.buttons.get(slot); - if(button != null && button.getClickEvent() != null) { - button.getClickEvent().accept(event); - } - - return event.isCancelled(); + public void previousPage() { + if(!this.hasPreviousPage()) return; + this.page--; + this.refresh(); } - public void close() {} + public abstract void setup(); + + public static Optional getPlayerMenu(Player player) { + return Optional.ofNullable(PLAYER_MENUS.get(player.getUniqueId())); + } - public abstract void build(); + public static void clearAll() { + Iterator> iterator = PLAYER_MENUS.entrySet().iterator(); + while(iterator.hasNext()) { + Map.Entry entry = iterator.next(); + entry.getValue().close(); + iterator.remove(); + } + } } diff --git a/src/main/java/com/github/hostadam/menu/MenuButton.java b/src/main/java/com/github/hostadam/menu/MenuButton.java deleted file mode 100644 index f30df1c..0000000 --- a/src/main/java/com/github/hostadam/menu/MenuButton.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.github.hostadam.menu; - -import com.github.hostadam.utils.ItemBuilder; -import lombok.Getter; -import lombok.Setter; -import org.bukkit.Material; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.inventory.ItemStack; - -import java.util.function.Consumer; - -@Getter -public class MenuButton extends ItemBuilder { - - @Setter - private int slot; - private Consumer clickEvent; - - public MenuButton(Material material) { - super(material); - } - - public MenuButton(ItemStack itemStack) { - super(itemStack); - } - - public MenuButton onClick(Consumer clickEvent) { - this.clickEvent = clickEvent; - return this; - } -} diff --git a/src/main/java/com/github/hostadam/menu/MenuHandler.java b/src/main/java/com/github/hostadam/menu/MenuHandler.java deleted file mode 100644 index 7470fcd..0000000 --- a/src/main/java/com/github/hostadam/menu/MenuHandler.java +++ /dev/null @@ -1,61 +0,0 @@ -package com.github.hostadam.menu; - -import org.bukkit.Bukkit; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.inventory.InventoryClickEvent; -import org.bukkit.event.inventory.InventoryCloseEvent; -import org.bukkit.event.player.PlayerQuitEvent; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.HashMap; -import java.util.Map; -import java.util.UUID; - -public class MenuHandler implements Listener { - - private final Map openMenus; - - public MenuHandler(JavaPlugin plugin) { - this.openMenus = new HashMap<>(); - Bukkit.getPluginManager().registerEvents(this, plugin); - } - - public void openMenu(Player player, Menu menu) { - menu.open(); - this.openMenus.put(player.getUniqueId(), menu); - } - - public void closeMenu(Player player) { - Menu menu = this.openMenus.remove(player.getUniqueId()); - if(menu != null) { - menu.close(); - } - } - - public Menu get(Player player) { - return this.openMenus.get(player.getUniqueId()); - } - - @EventHandler - public void onQuit(PlayerQuitEvent event) { - Player player = event.getPlayer(); - this.closeMenu(player); - } - - @EventHandler - public void onClose(InventoryCloseEvent event) { - Player player = (Player) event.getPlayer(); - this.closeMenu(player); - } - - @EventHandler - public void onClick(InventoryClickEvent event) { - Player player = (Player) event.getWhoClicked(); - Menu menu = this.get(player); - if(menu != null) { - menu.click(event); - } - } -} diff --git a/src/main/java/com/github/hostadam/menu/MenuItem.java b/src/main/java/com/github/hostadam/menu/MenuItem.java new file mode 100644 index 0000000..8825831 --- /dev/null +++ b/src/main/java/com/github/hostadam/menu/MenuItem.java @@ -0,0 +1,64 @@ +package com.github.hostadam.menu; + +import lombok.Getter; +import lombok.Setter; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.inventory.ItemStack; + +import java.util.function.Consumer; + +@Getter +public class MenuItem { + + @Setter + private ItemStack itemStack; + private ItemStack fallbackItem; + private String permission = ""; + private Type type = Type.NORMAL; + private Consumer clickEvent; + + public MenuItem(ItemStack itemStack) { + this.itemStack = itemStack; + } + + public MenuItem permission(String permission) { + this.permission = permission; + return this; + } + + public MenuItem onClick(Consumer clickEvent) { + this.clickEvent = clickEvent; + return this; + } + + public MenuItem type(Type type) { + this.type = type; + return this; + } + + public MenuItem fallback(ItemStack itemStack) { + this.fallbackItem = itemStack; + return this; + } + + public boolean isPaginated() { + return this.type != Type.NORMAL; + } + + public boolean hasFallbackItem() { + return this.fallbackItem != null; + } + + public MenuItem fromConfigSection(ConfigurationSection section) { + //TODO: This + return null; + } + + public enum Type { + NORMAL, + BACK_TO_MAIN_PAGE, + NEXT_PAGE, + PREVIOUS_PAGE; + } +} diff --git a/src/main/java/com/github/hostadam/menu/MenuListener.java b/src/main/java/com/github/hostadam/menu/MenuListener.java new file mode 100644 index 0000000..0942785 --- /dev/null +++ b/src/main/java/com/github/hostadam/menu/MenuListener.java @@ -0,0 +1,32 @@ +package com.github.hostadam.menu; + +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.player.PlayerQuitEvent; + +public class MenuListener implements Listener { + + @EventHandler + public void onQuit(PlayerQuitEvent event) { + Player player = event.getPlayer(); + Menu.getPlayerMenu(player).ifPresent(Menu::close); + } + + @EventHandler + public void onClose(InventoryCloseEvent event) { + Player player = (Player) event.getPlayer(); + Menu.getPlayerMenu(player).ifPresent(Menu::close); + } + + @EventHandler + public void onClick(InventoryClickEvent event) { + Player player = (Player) event.getWhoClicked(); + Menu.getPlayerMenu(player).ifPresent(newMenu -> { + boolean cancel = newMenu.click(event); + event.setCancelled(cancel); + }); + } +}