From ab4bb73cc113794af06ecb2533c69789020ac82d Mon Sep 17 00:00:00 2001 From: BuildTools Date: Thu, 21 Jan 2021 22:03:07 +0100 Subject: [PATCH] Initial commit --- .gitignore | 2 + pom.xml | 24 + src/main/java/nl/iobyte/menuapi/MenuAPI.java | 56 +++ .../java/nl/iobyte/menuapi/MenuListener.java | 100 ++++ .../iobyte/menuapi/action/HandlerAction.java | 23 + .../iobyte/menuapi/action/InteractAction.java | 18 + .../nl/iobyte/menuapi/action/MenuAction.java | 13 + .../java/nl/iobyte/menuapi/basic/Menu.java | 274 ++++++++++ .../java/nl/iobyte/menuapi/enums/Types.java | 28 ++ .../menuapi/interfaces/IActionHandler.java | 27 + .../nl/iobyte/menuapi/interfaces/IMenu.java | 130 +++++ .../iobyte/menuapi/interfaces/LoadAction.java | 9 + .../java/nl/iobyte/menuapi/item/Color.java | 14 + .../nl/iobyte/menuapi/item/ItemBuilder.java | 138 ++++++ .../java/nl/iobyte/menuapi/item/MenuItem.java | 150 ++++++ .../menuapi/map/WeakConcurrentHashMap.java | 96 ++++ .../nl/iobyte/menuapi/multi/MenuPage.java | 23 + .../nl/iobyte/menuapi/multi/MultiMenu.java | 467 ++++++++++++++++++ 18 files changed, 1592 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml create mode 100644 src/main/java/nl/iobyte/menuapi/MenuAPI.java create mode 100644 src/main/java/nl/iobyte/menuapi/MenuListener.java create mode 100644 src/main/java/nl/iobyte/menuapi/action/HandlerAction.java create mode 100644 src/main/java/nl/iobyte/menuapi/action/InteractAction.java create mode 100644 src/main/java/nl/iobyte/menuapi/action/MenuAction.java create mode 100644 src/main/java/nl/iobyte/menuapi/basic/Menu.java create mode 100644 src/main/java/nl/iobyte/menuapi/enums/Types.java create mode 100644 src/main/java/nl/iobyte/menuapi/interfaces/IActionHandler.java create mode 100644 src/main/java/nl/iobyte/menuapi/interfaces/IMenu.java create mode 100644 src/main/java/nl/iobyte/menuapi/interfaces/LoadAction.java create mode 100644 src/main/java/nl/iobyte/menuapi/item/Color.java create mode 100644 src/main/java/nl/iobyte/menuapi/item/ItemBuilder.java create mode 100644 src/main/java/nl/iobyte/menuapi/item/MenuItem.java create mode 100644 src/main/java/nl/iobyte/menuapi/map/WeakConcurrentHashMap.java create mode 100644 src/main/java/nl/iobyte/menuapi/multi/MenuPage.java create mode 100644 src/main/java/nl/iobyte/menuapi/multi/MultiMenu.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..744289d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +# Project exclude paths +/target/ \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..28ea0c1 --- /dev/null +++ b/pom.xml @@ -0,0 +1,24 @@ + + + 4.0.0 + + + 1.8 + 1.8 + + + nl.iobyte + menuapi + 1.0 + + + + org.spigotmc + spigot-api + 1.12.2-R0.1-SNAPSHOT + provided + + + \ No newline at end of file diff --git a/src/main/java/nl/iobyte/menuapi/MenuAPI.java b/src/main/java/nl/iobyte/menuapi/MenuAPI.java new file mode 100644 index 0000000..e4cfedb --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/MenuAPI.java @@ -0,0 +1,56 @@ +package nl.iobyte.menuapi; + +import nl.iobyte.menuapi.interfaces.IActionHandler; +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; +import java.util.HashMap; + +public class MenuAPI { + + private static boolean registered = false; + private static final HashMap actionHandlers = new HashMap<>(); + + /** + * Add ActionHandler + * @param handler IActionHandler + */ + public static void addActionHandler(IActionHandler handler) { + actionHandlers.put(handler.getID(), handler); + } + + /** + * Get IActionHandler by ID + * @param id String + * @return IActionHandler + */ + public static IActionHandler getActionHandler(String id) { + return actionHandlers.get(id); + } + + /** + * Has IActionHandler with specific ID + * @param id String + * @return Boolean + */ + public static boolean hasActionHandler(String id) { + return actionHandlers.containsKey(id); + } + + /** + * Remove IActionHandler by ID + * @param id String + * @return IActionHandler + */ + public static IActionHandler removeActionHandler(String id) { + return actionHandlers.remove(id); + } + + public static void register(Plugin plugin) { + if(registered || plugin == null) + return; + + Bukkit.getPluginManager().registerEvents(new MenuListener(), plugin); + registered = true; + } + +} diff --git a/src/main/java/nl/iobyte/menuapi/MenuListener.java b/src/main/java/nl/iobyte/menuapi/MenuListener.java new file mode 100644 index 0000000..a239d45 --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/MenuListener.java @@ -0,0 +1,100 @@ +package nl.iobyte.menuapi; + +import nl.iobyte.menuapi.interfaces.IMenu; +import nl.iobyte.menuapi.action.InteractAction; +import nl.iobyte.menuapi.multi.MenuPage; +import nl.iobyte.menuapi.multi.MultiMenu; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.*; +import org.bukkit.inventory.Inventory; + +public class MenuListener implements Listener { + + @EventHandler + public void onClick(InventoryClickEvent e) { + if(e.getClickedInventory() == null) + return; + + Inventory inventory = e.getClickedInventory(); + if(!(inventory.getHolder() instanceof IMenu)) + return; + + if(e.isCancelled()) + return; + + Player player = (Player) e.getWhoClicked(); + int slot = e.getRawSlot(); + ClickType type = e.getClick(); + + IMenu menu = (IMenu) inventory.getHolder(); + e.setCancelled(menu.execute(player, slot, type)); + } + + @EventHandler + public void onOpen(InventoryOpenEvent e) { + Player player = (Player) e.getPlayer(); + Inventory inventory = e.getInventory(); + if(!(inventory.getHolder() instanceof IMenu)) + return; + + if(!(inventory.getHolder() instanceof MenuPage)) { + IMenu menu = (IMenu) inventory.getHolder(); + InteractAction open = menu.getOpenAction(); + if (open == null) + return; + + open.execute(player); + e.setCancelled(open.doCancel()); + } else { + MenuPage page = (MenuPage) inventory.getHolder(); + MultiMenu menu = page.getParent(); + if(!menu.isActivePage(player.getUniqueId(), page)) + return; + + InteractAction open = menu.getOpenAction(); + if (open == null) + return; + + open.execute(player); + e.setCancelled(open.doCancel()); + } + } + + @EventHandler + public void onClose(InventoryCloseEvent e) { + Player player = (Player) e.getPlayer(); + Inventory inventory = e.getInventory(); + if(!(inventory.getHolder() instanceof IMenu)) + return; + + if(!(inventory.getHolder() instanceof MenuPage)) { + IMenu menu = (IMenu) inventory.getHolder(); + InteractAction close = menu.getCloseAction(); + if(close == null) + return; + + close.execute(player); + if(close.doCancel()) + menu.open(player); + } else { + MenuPage page = (MenuPage) inventory.getHolder(); + MultiMenu menu = page.getParent(); + if(!menu.isActivePage(player.getUniqueId(), page)) + return; + + InteractAction close = menu.getCloseAction(); + if (close == null) + return; + + close.execute(player); + if(close.doCancel()) { + page.open(player); + } else { + menu.close(player); + } + } + } + +} diff --git a/src/main/java/nl/iobyte/menuapi/action/HandlerAction.java b/src/main/java/nl/iobyte/menuapi/action/HandlerAction.java new file mode 100644 index 0000000..315e3ff --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/action/HandlerAction.java @@ -0,0 +1,23 @@ +package nl.iobyte.menuapi.action; + +import nl.iobyte.menuapi.MenuAPI; +import nl.iobyte.menuapi.interfaces.IActionHandler; +import org.bukkit.entity.Player; + +public class HandlerAction extends MenuAction { + + private final String handler; + + public HandlerAction(String handler) { + this.handler = handler; + } + + public void execute(Player player) { + IActionHandler handler = MenuAPI.getActionHandler(this.handler); + if(handler == null) + return; + + handler.execute(player); + } + +} diff --git a/src/main/java/nl/iobyte/menuapi/action/InteractAction.java b/src/main/java/nl/iobyte/menuapi/action/InteractAction.java new file mode 100644 index 0000000..abcfc95 --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/action/InteractAction.java @@ -0,0 +1,18 @@ +package nl.iobyte.menuapi.action; + +public abstract class InteractAction extends MenuAction { + + /** + * Set if should cancel + * @param cancel boolean + * @return InteractAction + */ + public abstract InteractAction setCancel(boolean cancel); + + /** + * Check if should cancel + * @return boolean + */ + public abstract boolean doCancel(); + +} diff --git a/src/main/java/nl/iobyte/menuapi/action/MenuAction.java b/src/main/java/nl/iobyte/menuapi/action/MenuAction.java new file mode 100644 index 0000000..f3544d6 --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/action/MenuAction.java @@ -0,0 +1,13 @@ +package nl.iobyte.menuapi.action; + +import org.bukkit.entity.Player; + +public abstract class MenuAction { + + /** + * Execute Action for Player + * @param player Player instance + */ + public abstract void execute(Player player); + +} diff --git a/src/main/java/nl/iobyte/menuapi/basic/Menu.java b/src/main/java/nl/iobyte/menuapi/basic/Menu.java new file mode 100644 index 0000000..57bee31 --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/basic/Menu.java @@ -0,0 +1,274 @@ +package nl.iobyte.menuapi.basic; + +import nl.iobyte.menuapi.action.InteractAction; +import nl.iobyte.menuapi.action.MenuAction; +import nl.iobyte.menuapi.interfaces.IMenu; +import nl.iobyte.menuapi.item.Color; +import nl.iobyte.menuapi.item.MenuItem; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class Menu implements IMenu { + + private String title; + private int size; + private final HashMap items = new HashMap<>(); + private InteractAction open, close; + private Inventory inventory; + private boolean locked = true; + + public Menu(String title, int size) { + this.title = title; + this.size = size; + } + + public Menu(String title, int size, boolean locked) { + this.title = title; + this.size = size; + this.locked = locked; + } + + /** + * Return inventory size + * @return int + */ + public int getSize() { + return size; + } + + /** + * Set size + * @param size int + * @return IMenu + */ + public IMenu setSize(int size) { + this.size = size; + return this; + } + + /** + * Get item + * @param slot int + * @return MenuItem + */ + public MenuItem getItem(int slot) { + if(!items.containsKey(slot)) + return null; + + return items.get(slot); + } + + /** + * Get menu items + * @return MenuItem + */ + public HashMap getItems() { + return items; + } + + /** + * Set item to slot + * @param slot int + * @param item MenuItem + * @return IMenu + */ + public IMenu setItem(int slot, MenuItem item) { + if(slot < 0 || slot >= size) + return this; + + items.put(slot, item); + return this; + } + + /** + * Set item to slot + * @param slot int + * @param item ItemStack + * @return IMenu + */ + public IMenu setItem(int slot, ItemStack item) { + MenuItem mi = getItem(slot); + if(mi == null) + return this; + + mi.setItem(item); + return this; + } + + public IMenu setItems(HashMap items) { + items.replaceAll((k, v) -> v.clone()); + return this; + } + + /** + * Update item + * @param slot int + * @return IMenu + */ + public IMenu updateItem(int slot) { + MenuItem item = getItem(slot); + if(item == null) + return this; + + inventory.setItem(slot, item.getItem()); + return this; + } + + /** + * Get action on open + * @return InteractAction + */ + public InteractAction getOpenAction() { + return open; + } + + /** + * Set action on open + * @param action InteractAction + * @return IMenu + */ + public IMenu setOpenAction(InteractAction action) { + open = action; + return this; + } + + /** + * Get action on close + * @return InteractAction + */ + public InteractAction getCloseAction() { + return close; + } + + /** + * Set action on close + * @param action InteractAction + * @return IMenu + */ + public IMenu setCloseAction(InteractAction action) { + close = action; + return this; + } + + /** + * Get menu title + * @return String + */ + public String getTitle() { + return title; + } + + /** + * Set menu title + * @param title String + * @return IMenu + */ + public IMenu setTitle(String title) { + this.title = title; + return this; + } + + /** + * Get if Menu is locked + * @return Boolean + */ + public boolean isLocked() { + return locked; + } + + /** + * Set if menu is locked + * @param locked Boolean + * @return IMenu + */ + public IMenu setLocked(boolean locked) { + this.locked = locked; + return this; + } + + /** + * Build Menu + * @return IMenu + */ + public IMenu build() { + inventory = Bukkit.createInventory(this, toSize(size, 9), Color.parse(title)); + for(Map.Entry entrySet : items.entrySet()) + if(entrySet.getKey() < size) + inventory.setItem(entrySet.getKey(), entrySet.getValue().getItem()); + + return this; + } + + /** + * Number to size + * @param i int + * @param size int + * @return int + */ + protected static int toSize(int i, int size) { + int r = i % size; + if(r > 0) + i += size - r; + + return i; + } + + /** + * Get inventory + * @return Inventory + */ + public Inventory getInventory() { + return inventory; + } + + /** + * Execute Click + * @param player Player + * @param slot int + * @param type ClickType + * @return cancel + */ + public boolean execute(Player player, int slot, ClickType type) { + if(player == null || type == null) + return locked; + + if(slot < 0 || slot >= size) + return locked; + + MenuItem item = getItem(slot); + if(item == null) + return locked; + + ArrayList actions = item.getActions(type); + if(actions != null && !actions.isEmpty()) + for(MenuAction action : actions) + action.execute(player); + + return item.doCancel(); + } + + /** + * Open menu for player + * @param player Player + */ + public void open(Player player) { + if(inventory == null) + return; + + player.openInventory(inventory); + } + + @Override + public Menu clone() { + Menu menu = new Menu(title, size); + menu.setItems(items); + return menu; + } + +} diff --git a/src/main/java/nl/iobyte/menuapi/enums/Types.java b/src/main/java/nl/iobyte/menuapi/enums/Types.java new file mode 100644 index 0000000..0ee700f --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/enums/Types.java @@ -0,0 +1,28 @@ +package nl.iobyte.menuapi.enums; + +import org.bukkit.event.inventory.ClickType; +import java.util.Arrays; +import java.util.List; + +public enum Types { + + LEFT(ClickType.LEFT, ClickType.SHIFT_LEFT), + RIGHT(ClickType.RIGHT, ClickType.SHIFT_RIGHT), + NORMAL(ClickType.LEFT, ClickType.RIGHT), + SHIFT(ClickType.SHIFT_LEFT, ClickType.SHIFT_RIGHT), + WINDOW_BORDER(ClickType.WINDOW_BORDER_LEFT, ClickType.WINDOW_BORDER_RIGHT); + + private final ClickType[] types; + Types(ClickType... types) { + this.types = types; + } + + public ClickType[] getTypes() { + return types; + } + + public List getTypesList() { + return Arrays.asList(types); + } + +} diff --git a/src/main/java/nl/iobyte/menuapi/interfaces/IActionHandler.java b/src/main/java/nl/iobyte/menuapi/interfaces/IActionHandler.java new file mode 100644 index 0000000..2022e54 --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/interfaces/IActionHandler.java @@ -0,0 +1,27 @@ +package nl.iobyte.menuapi.interfaces; + +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import java.util.List; + +public interface IActionHandler { + + /** + * Get ID of the handler + * @return String + */ + String getID(); + + /** + * Get ClickType's of handler + * @return List + */ + List getClickTypes(); + + /** + * Action to perform on click + * @param player Player + */ + void execute(Player player); + +} diff --git a/src/main/java/nl/iobyte/menuapi/interfaces/IMenu.java b/src/main/java/nl/iobyte/menuapi/interfaces/IMenu.java new file mode 100644 index 0000000..1996e6e --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/interfaces/IMenu.java @@ -0,0 +1,130 @@ +package nl.iobyte.menuapi.interfaces; + +import nl.iobyte.menuapi.action.InteractAction; +import nl.iobyte.menuapi.item.MenuItem; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; + +import java.util.HashMap; + +public interface IMenu extends InventoryHolder { + + /** + * Get item + * @param slot int + * @return MenuItem + */ + MenuItem getItem(int slot); + + /** + * Get menu items + * @return MenuItem + */ + HashMap getItems(); + + /** + * Set item to slot + * @param slot int + * @param item MenuItem + * @return IMenu + */ + IMenu setItem(int slot, MenuItem item); + + /** + * Set item to slot + * @param slot int + * @param item ItemStack + * @return IMenu + */ + IMenu setItem(int slot, ItemStack item); + + /** + * Set menu items + * @param items MenuItems + * @return IMenu + */ + IMenu setItems(HashMap items); + + /** + * Update item + * @param slot int + * @return IMenu + */ + IMenu updateItem(int slot); + + /** + * Get action on open + * @return InteractAction + */ + InteractAction getOpenAction(); + + /** + * Set action on open + * @param action InteractAction + * @return IMenu + */ + IMenu setOpenAction(InteractAction action); + + /** + * Get action on close + * @return InteractAction + */ + InteractAction getCloseAction(); + + /** + * Set action on close + * @param action InteractAction + * @return IMenu + */ + IMenu setCloseAction(InteractAction action); + + /** + * Get menu title + * @return String + */ + String getTitle(); + + /** + * Set menu title + * @param title String + * @return IMenu + */ + IMenu setTitle(String title); + + /** + * Build Menu + * @return IMenu + */ + IMenu build(); + + /** + * Get inventory + * @return Inventory + */ + Inventory getInventory(); + + /** + * Execute Click + * @param player Player + * @param slot int + * @param type ClickType + * @return cancel + */ + boolean execute(Player player, int slot, ClickType type); + + /** + * Open menu for player + * @param player Player + */ + void open(Player player); + + /** + * Clone Menu + * @return IMenu + */ + IMenu clone(); + +} diff --git a/src/main/java/nl/iobyte/menuapi/interfaces/LoadAction.java b/src/main/java/nl/iobyte/menuapi/interfaces/LoadAction.java new file mode 100644 index 0000000..8654686 --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/interfaces/LoadAction.java @@ -0,0 +1,9 @@ +package nl.iobyte.menuapi.interfaces; + +import org.bukkit.entity.Player; + +public interface LoadAction { + + void run(IMenu menu, Player player); + +} diff --git a/src/main/java/nl/iobyte/menuapi/item/Color.java b/src/main/java/nl/iobyte/menuapi/item/Color.java new file mode 100644 index 0000000..ccab65f --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/item/Color.java @@ -0,0 +1,14 @@ +package nl.iobyte.menuapi.item; + +import org.bukkit.ChatColor; + +public class Color { + + public static String parse(String str) { + if(str == null || str.isEmpty()) + return str; + + return ChatColor.translateAlternateColorCodes('&', str); + } + +} diff --git a/src/main/java/nl/iobyte/menuapi/item/ItemBuilder.java b/src/main/java/nl/iobyte/menuapi/item/ItemBuilder.java new file mode 100644 index 0000000..5803df9 --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/item/ItemBuilder.java @@ -0,0 +1,138 @@ +package nl.iobyte.menuapi.item; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +public class ItemBuilder { + + private final ItemStack item; + + public ItemBuilder(ItemStack item) { + this.item = item; + } + + public ItemBuilder(Material material) { + item = new ItemStack(material, 1); + } + + public ItemBuilder(Material material, int amount) { + item = new ItemStack(material, amount); + } + + public ItemBuilder(Material material, int amount, short data) { + item = new ItemStack(material, amount, data); + } + + public ItemStack getItem() { + return item; + } + + public ItemBuilder setType(Material material) { + if(material == null) + return this; + + item.setType(material); + return this; + } + + public ItemBuilder setUnbreakable(boolean b) { + ItemMeta meta = item.getItemMeta(); + meta.setUnbreakable(b); + item.setItemMeta(meta); + return this; + } + + public ItemBuilder setName(String name) { + if(name == null) + return this; + + ItemMeta meta = item.getItemMeta(); + meta.setDisplayName(Color.parse(name)); + this.item.setItemMeta(meta); + return this; + } + + public ItemBuilder setLore(List lore) { + if(lore == null) + return this; + + ItemMeta meta = item.getItemMeta(); + for(String string : lore) + lore.set(lore.indexOf(string), Color.parse(string)); + + meta.setLore(lore); + item.setItemMeta(meta); + return this; + } + + public ItemBuilder setLore(String lore) { + List list = new ArrayList<>(); + list.add(lore); + setLore(list); + return this; + } + + public ItemBuilder addLore(String lore) { + List list = item.getItemMeta().getLore(); + list.add(lore); + setLore(list); + return this; + } + + public ItemBuilder setEnchantment(HashMap enchantments) { + ItemMeta meta = item.getItemMeta(); + if(!meta.getEnchants().isEmpty()) + meta.getEnchants().clear(); + + for(Map.Entry entry : enchantments.entrySet()) + meta.addEnchant(entry.getKey(), entry.getValue(), true); + + item.setItemMeta(meta); + return this; + } + + public ItemBuilder setEnchantment(Enchantment enchantment, int i) { + ItemMeta meta = item.getItemMeta(); + if (!meta.getEnchants().isEmpty()) + meta.getEnchants().clear(); + + meta.addEnchant(enchantment, i, true); + item.setItemMeta(meta); + return this; + } + + public ItemBuilder addEnchantment(Enchantment enchantment, int i) { + ItemMeta meta = item.getItemMeta(); + meta.addEnchant(enchantment, i, true); + item.setItemMeta(meta); + return this; + } + + public ItemBuilder addFlag(ItemFlag flag) { + ItemMeta meta = item.getItemMeta(); + meta.addItemFlags(flag); + item.setItemMeta(meta); + return this; + } + + public ItemBuilder addFlags(ItemFlag... flags) { + ItemMeta meta = item.getItemMeta(); + meta.addItemFlags(flags); + item.setItemMeta(meta); + return this; + } + + public ItemBuilder clone() { + return new ItemBuilder(item.clone()); + } + +} \ No newline at end of file diff --git a/src/main/java/nl/iobyte/menuapi/item/MenuItem.java b/src/main/java/nl/iobyte/menuapi/item/MenuItem.java new file mode 100644 index 0000000..90fccfa --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/item/MenuItem.java @@ -0,0 +1,150 @@ +package nl.iobyte.menuapi.item; + +import nl.iobyte.menuapi.action.HandlerAction; +import nl.iobyte.menuapi.interfaces.IActionHandler; +import nl.iobyte.menuapi.action.MenuAction; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.ItemStack; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class MenuItem { + + private ItemStack item; + private boolean cancel; + private HashMap> actions = new HashMap<>(); + + public MenuItem(ItemStack item, boolean cancel) { + this.item = item; + this.cancel = cancel; + } + + /** + * Get item + * @return ItemStack instance + */ + public ItemStack getItem() { + return item; + } + + /** + * Set item + * @param item ItemStack instance + * @return MenuItem instance + */ + public MenuItem setItem(ItemStack item) { + this.item = item; + return this; + } + + /** + * Get Actions for ClickType + * @param type Type of Click + * @return Array of MenuActions + */ + public ArrayList getActions(ClickType type) { + if(type == null) + return null; + + if(!actions.containsKey(type)) + return null; + + return actions.get(type); + } + + /** + * Add actions to MenuItem + * @param type ClickType + * @param actions Array of MenuActions + * @return MenuItem Instance + */ + public MenuItem addActions(ClickType type, MenuAction... actions) { + if(type == null || actions == null) + return this; + + ArrayList array = new ArrayList<>(); + if(this.actions.containsKey(type)) { + array = this.actions.get(type); + } else { + this.actions.put(type, array); + } + + array.addAll(Arrays.asList(actions)); + return this; + } + + /** + * Add actions to MenuItem + * @param types List of ClickType + * @param actions Array of MenuActions + * @return MenuItem Instance + */ + public MenuItem addActions(List types, MenuAction... actions) { + for(ClickType type : types) + addActions(type, actions); + + return this; + } + + /** + * Add actions to MenuItem for any type of Click + * @param actions Array of MenuActions + * @return MenuItem Instance + */ + public MenuItem addActions(MenuAction... actions) { + for(ClickType type : ClickType.values()) { + addActions(type, actions); + addActions(type, actions); + } + + return this; + } + + /** + * Add actions to MenuItem + * @param handlers IActionHandler[] + * @return MenuItem Instance + */ + public MenuItem addActions(IActionHandler... handlers) { + for(IActionHandler handler : handlers) + addActions(handler.getClickTypes(), new MenuAction() { + public void execute(Player player) { + handler.execute(player); + } + }); + + return this; + } + + /** + * Get if should do cancel + * @return boolean + */ + public boolean doCancel() { + return cancel; + } + + /** + * Set if should do cancel + * @param cancel boolean + * @return MenuItem Instance + */ + public MenuItem setCancel(boolean cancel) { + this.cancel = cancel; + return this; + } + + /** + * Clone menu item + * @return MenuItem + */ + public MenuItem clone() { + MenuItem mi = new MenuItem(item.clone(), cancel); + mi.actions = actions; + return mi; + } + +} diff --git a/src/main/java/nl/iobyte/menuapi/map/WeakConcurrentHashMap.java b/src/main/java/nl/iobyte/menuapi/map/WeakConcurrentHashMap.java new file mode 100644 index 0000000..d60197b --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/map/WeakConcurrentHashMap.java @@ -0,0 +1,96 @@ +package nl.iobyte.menuapi.map; + +import java.util.Date; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + +public class WeakConcurrentHashMap extends ConcurrentHashMap { + + private Map timeMap = new ConcurrentHashMap<>(); + private long expiryInMillis; + private boolean mapAlive = true; + + public WeakConcurrentHashMap() { + this.expiryInMillis = 10 * 1000; + initialize(); + } + + public WeakConcurrentHashMap(long expiryInMillis) { + this.expiryInMillis = expiryInMillis; + initialize(); + } + + void initialize() { + new CleanerThread().start(); + } + + @Override + public V put(K key, V value) { + if (!mapAlive) + throw new IllegalStateException("WeakConcurrent Hashmap is no more alive.. Try creating a new one."); + + Date date = new Date(); + timeMap.put(key, date.getTime()); + return super.put(key, value); + } + + @Override + @SuppressWarnings("unchecked") + public V get(Object key) { + if (!mapAlive) + throw new IllegalStateException("WeakConcurrent Hashmap is no more alive.. Try creating a new one."); + + Date date = new Date(); + timeMap.put((K) key, date.getTime()); + return super.get(key); + } + + @Override + public void putAll(Map m) { + if (!mapAlive) + throw new IllegalStateException("WeakConcurrent Hashmap is no more alive.. Try creating a new one."); + + for (K key : m.keySet()) + put(key, m.get(key)); + } + + @Override + public V putIfAbsent(K key, V value) { + if (!mapAlive) + throw new IllegalStateException("WeakConcurrent Hashmap is no more alive.. Try creating a new one."); + + return !containsKey(key) ? put(key, value) : get(key); + } + + public void quitMap() { + mapAlive = false; + } + + public boolean isAlive() { + return mapAlive; + } + + class CleanerThread extends Thread { + + @Override + public void run() { + while (mapAlive) { + cleanMap(); + try { + Thread.sleep(expiryInMillis / 2); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + private void cleanMap() { + long currentTime = new Date().getTime(); + for (K key : timeMap.keySet()) + if (currentTime > (timeMap.get(key) + expiryInMillis)) + timeMap.remove(key); + } + + } + +} \ No newline at end of file diff --git a/src/main/java/nl/iobyte/menuapi/multi/MenuPage.java b/src/main/java/nl/iobyte/menuapi/multi/MenuPage.java new file mode 100644 index 0000000..48a355d --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/multi/MenuPage.java @@ -0,0 +1,23 @@ +package nl.iobyte.menuapi.multi; + +import nl.iobyte.menuapi.basic.Menu; + +public class MenuPage extends Menu { + + private final MultiMenu menu; + + public MenuPage(String title, int size, MultiMenu menu) { + super(title, size); + this.menu = menu; + } + + public MenuPage(String title, int size, boolean locked, MultiMenu menu) { + super(title, size, locked); + this.menu = menu; + } + + public MultiMenu getParent() { + return menu; + } + +} diff --git a/src/main/java/nl/iobyte/menuapi/multi/MultiMenu.java b/src/main/java/nl/iobyte/menuapi/multi/MultiMenu.java new file mode 100644 index 0000000..dd0924b --- /dev/null +++ b/src/main/java/nl/iobyte/menuapi/multi/MultiMenu.java @@ -0,0 +1,467 @@ +package nl.iobyte.menuapi.multi; + +import nl.iobyte.menuapi.action.InteractAction; +import nl.iobyte.menuapi.interfaces.IMenu; +import nl.iobyte.menuapi.item.MenuItem; +import org.bukkit.entity.Player; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; + +public class MultiMenu implements IMenu { + + private String title; + private ArrayList page_sizes; + private InteractAction open, close; + private boolean locked = true; + + private final HashMap pages = new HashMap<>(); + private final HashMap page_data = new HashMap<>(); + + public MultiMenu(String title, ArrayList page_sizes) { + this.title = title; + this.page_sizes = page_sizes; + buildPages(); + } + + public MultiMenu(String title, ArrayList page_sizes, boolean locked) { + this.title = title; + this.page_sizes = page_sizes; + this.locked = locked; + buildPages(); + } + + /** + * Return inventory sizes + * @return int + */ + public ArrayList getPageSizes() { + return page_sizes; + } + + /** + * Set sizes + * @param page_sizes int + * @return IMenu + */ + public IMenu setPageSizes(ArrayList page_sizes) { + this.page_sizes = page_sizes; + buildPages(); + + return this; + } + + /** + * Get item of first page + * @param slot int + * @return MenuItem + */ + public MenuItem getItem(int slot) { + int[] data = getSlot(slot); + if(data == null) + return null; + + return getItem(data[0], data[1]); + } + + /** + * Get item on page + * @param page int + * @param slot int + * @return MenuItem + */ + public MenuItem getItem(int page, int slot) { + MenuPage mp = getPage(page); + if(mp == null) + return null; + + return mp.getItem(slot); + } + + /** + * Get items of first page + * @return IMenu + */ + public HashMap getItems() { + return getItems(1); + } + + /** + * Get items of MenuPage + * @param page int + * @return HashMap + */ + public HashMap getItems(int page) { + if(page < 1) + return null; + + MenuPage mp = pages.get(page); + if(mp == null) + return null; + + return mp.getItems(); + } + + /** + * Set item to slot on first page + * @param slot int + * @param item MenuItem + * @return IMenu + */ + public IMenu setItem(int slot, MenuItem item) { + int[] data = getSlot(slot); + if(data == null) + return this; + + return setItem(data[0], data[1], item); + } + + /** + * Set item to slot on page + * @param page int + * @param slot int + * @param item MenuItem + * @return IMenu + */ + public IMenu setItem(int page, int slot, MenuItem item) { + MenuPage mp = getPage(page); + if(mp == null) + return this; + + return mp.setItem(slot, item); + } + + /** + * Set item to slot on first page + * @param slot int + * @param item ItemStack + * @return IMenu + */ + public IMenu setItem(int slot, ItemStack item) { + int[] data = getSlot(slot); + if(data == null) + return this; + + return setItem(data[0], data[1], item); + } + + /** + * Set item to slot on page + * @param page int + * @param slot int + * @param item ItemStack + * @return IMenu + */ + public IMenu setItem(int page, int slot, ItemStack item) { + MenuPage mp = getPage(page); + if(mp == null) + return this; + + mp.setItem(slot, item); + return mp.setItem(slot, item); + } + + /** + * Set items for first page + * @param items MenuItems + * @return IMenu + */ + public MultiMenu setItems(HashMap items) { + return setItems(1, items); + } + + /** + * Set items for MenuPage + * @param page int + * @param items HashMap + * @return IMenu + */ + public MultiMenu setItems(int page, HashMap items) { + if(page < 1) + return this; + + MenuPage mp = pages.get(page); + if(mp == null) + return this; + + mp.setItems(items); + return this; + } + + /** + * Update item on first page + * @param slot int + * @return IMenu + */ + public IMenu updateItem(int slot) { + int[] data = getSlot(slot); + if(data == null) + return this; + + return updateItem(data[0], data[1]); + } + + /** + * Update item on page + * @param page int + * @param slot int + * @return IMenu + */ + public IMenu updateItem(int page, int slot) { + MenuPage mp = getPage(page); + if(mp == null) + return this; + + mp.updateItem(slot); + return this; + } + + /** + * Get page from slot + * @param slot int + * @return int + */ + public int[] getSlot(int slot) { + int page = 1; + int temp = slot; + for(int size : page_sizes) { + temp -= size; + if(temp < 0) { + temp += size; + return new int[]{ + page, temp + }; + } + + page++; + } + + return null; + } + + /** + * Get MenuPage + * @param page int + * @return MenuPage + */ + public MenuPage getPage(int page) { + if(!pages.containsKey(page)) + return null; + + return pages.get(page); + } + + /** + * Get MenuPages + * @return HashMap + */ + public HashMap getPages() { + return pages; + } + + /** + * Get action on open + * @return InteractAction + */ + public InteractAction getOpenAction() { + return open; + } + + /** + * Set action on open + * @param action InteractAction + * @return IMenu + */ + public IMenu setOpenAction(InteractAction action) { + open = action; + return this; + } + + /** + * Get action on close + * @return InteractAction + */ + public InteractAction getCloseAction() { + return close; + } + + /** + * Set action on close + * @param action InteractAction + * @return IMenu + */ + public IMenu setCloseAction(InteractAction action) { + close = action; + return this; + } + + /** + * Get menu title + * @return String + */ + public String getTitle() { + return title; + } + + /** + * Set menu title + * @param title String + * @return IMenu + */ + public IMenu setTitle(String title) { + this.title = title; + return this; + } + + /** + * Get if menu is locked + * @return Boolean + */ + public boolean isLocked() { + return locked; + } + + /** + * Set if menu is locked + * @param locked Boolean + * @return IMenu + */ + public IMenu setLocked(boolean locked) { + this.locked = locked; + for(MenuPage page : page_data.values()) + page.setLocked(locked); + + return this; + } + + /** + * Build Menu + * @return IMenu + */ + public IMenu build() { + for(MenuPage page : pages.values()) + page.build(); + + return this; + } + + /** + * Get menu pages + * @return IMenu + */ + public IMenu buildPages() { + int i = 1; + for(int size : page_sizes) { + MenuPage page = getPage(i); + if(page == null) { + page = new MenuPage(title, size, locked,this); + } else{ + page.setSize(size); + } + + pages.put(i, page); + i++; + } + + int difference = pages.size() - page_sizes.size(); + if(difference > 0) + for(int j = 0; j < difference; j++) + pages.remove(page_sizes.size() + j); + + return this; + } + + /** + * Return null + * @return Inventory + */ + public Inventory getInventory() { + MenuPage mp = pages.get(1); + if(mp == null) + return null; + + return mp.getInventory(); + } + + /** + * Execute non existing Click + * @param player Player + * @param slot int + * @param type ClickType + * @return cancel + */ + public boolean execute(Player player, int slot, ClickType type) { + return true; + } + + /** + * See if MenuPage is open for User + * @param uuid UUID + * @param page MenuPage + * @return boolean + */ + public boolean isActivePage(UUID uuid, MenuPage page) { + if(uuid == null || page == null) + return false; + + if(!page_data.containsKey(uuid)) + return false; + + MenuPage mp = page_data.get(uuid); + return mp == page; + } + + /** + * Open first page of inventory + * @param player Player + */ + public void open(Player player) { + open(player, 1); + } + + /** + * Open page of invetory + * @param player Player + * @param page int + */ + public void open(Player player, int page) { + if(player == null || page < 1) + return; + + if(!pages.containsKey(page)) + return; + + MenuPage mp = pages.get(page); + page_data.put(player.getUniqueId(), mp); + mp.open(player); + } + + /** + * Close inventory of Player + * @param player Player + */ + public void close(Player player) { + if(player == null) + return; + + page_data.remove(player.getUniqueId()); + player.closeInventory(); + } + + /** + * Clone Menu + * @return MultiMenu + */ + public MultiMenu clone() { + MultiMenu menu = new MultiMenu(title, page_sizes); + for(Map.Entry entrySet : pages.entrySet()) + menu.setItems(entrySet.getKey(), entrySet.getValue().getItems()); + + return menu; + } + +}