From 38a98043d55c11b2bcf584800f1241164235fb3d Mon Sep 17 00:00:00 2001 From: Tastybento Date: Sat, 25 Nov 2017 18:17:16 -0800 Subject: [PATCH] First commit --- README.md | 1 + config.yml | 305 +++++++++++++ locales/bsb_en_US.yml | 8 + plugin.yml | 22 + pom.xml | 63 +++ .../addin/challenges/AddonHelper.java | 36 ++ .../addin/challenges/Challenges.java | 94 ++++ .../addin/challenges/ChallengesManager.java | 257 +++++++++++ .../commands/ChallengesCommand.java | 86 ++++ .../challenges/config/LocaleManager.java | 28 ++ .../addin/challenges/config/PluginConfig.java | 95 +++++ .../addin/challenges/config/Settings.java | 22 + .../database/object/ChallengesDO.java | 401 ++++++++++++++++++ .../challenges/database/object/LevelsDO.java | 61 +++ .../addin/challenges/panel/Panel.java | 202 +++++++++ 15 files changed, 1681 insertions(+) create mode 100644 README.md create mode 100644 config.yml create mode 100755 locales/bsb_en_US.yml create mode 100755 plugin.yml create mode 100644 pom.xml create mode 100644 src/bskyblock/addin/challenges/AddonHelper.java create mode 100644 src/bskyblock/addin/challenges/Challenges.java create mode 100644 src/bskyblock/addin/challenges/ChallengesManager.java create mode 100644 src/bskyblock/addin/challenges/commands/ChallengesCommand.java create mode 100644 src/bskyblock/addin/challenges/config/LocaleManager.java create mode 100644 src/bskyblock/addin/challenges/config/PluginConfig.java create mode 100644 src/bskyblock/addin/challenges/config/Settings.java create mode 100644 src/bskyblock/addin/challenges/database/object/ChallengesDO.java create mode 100644 src/bskyblock/addin/challenges/database/object/LevelsDO.java create mode 100644 src/bskyblock/addin/challenges/panel/Panel.java diff --git a/README.md b/README.md new file mode 100644 index 0000000..e1cb18b --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +# addon-challenges diff --git a/config.yml b/config.yml new file mode 100644 index 0000000..15b3707 --- /dev/null +++ b/config.yml @@ -0,0 +1,305 @@ +# This file lists the values for various blocks that are used to calculate the +# island level. Level = total of all blocks in island boundary / 100. +# Players with the permission askyblock.island.multiplier.# will have their blocks +# multiplied in value by that amount. + +# Underwater block multiplier +# If blocks are below sea-level, they can have a higher value. e.g. 2x +# Promotes under-water development if there is a sea. Value can be fractional. +underwater: 1.0 + +# Value of one island level. Default 100. Minimum value is 1. +levelcost: 100 + +# Cooldown between level requests in seconds +levelwait: 60 + +# Death penalty +# How many block values a player will lose per death. +# Default value of 100 means that for every death, the player will lose 1 level (if levelcost is 100) +# Set to zero to not use this feature +deathpenalty: 100 +# Sum team deaths - if true, all the teams deaths are summed +# If false, only the leader's deaths counts +sumteamdeaths: false +# Max deaths +# If player dies more than this, it doesn't count anymore +# Stops players from getting into an impossible situation +maxdeaths: 10 +# Reset deaths on island reset +islandresetdeathreset: true +# Reset deaths on team join +teamjoindeathreset: true + + +# This section lists the limits for any particular block. Blocks over this amount +# are not counted. +# Format: +# MATERIAL: limit or MATERIAL:DATA: limit. +# If DATA is used, there MUST be a corresponding block:data value in the blocks list. +# For example, if you limit Jungle Logs LOG:3, then there must be a value for LOG:3 +# in the blocks section. If there is not, then LOG:3 would have no value. +limits: + COBBLESTONE: 10000 + NETHERRACK: 1000 + #LOG:3: 10 + +# This section lists the value of a block. Value must be an integer. +# Any blocks not listed will have a value of zero. +# Format is MATERIAL: value or MATERIAL:DATA: value. + +blocks: + ACACIA_DOOR: 1 + ACACIA_STAIRS: 1 + ACACIA_FENCE: 1 + ACACIA_FENCE_GATE: 1 + ACACIA_STAIRS: 2 + ACTIVATOR_RAIL: 10 + AIR: 0 + ANVIL: 10 + ARMOR_STAND: 2 + BANNER: 2 + BEACON: 100 + BED_BLOCK: 1 + BEDROCK: 0 + BEETROOT_BLOCK: 1 + BIRCH_DOOR: 1 + BIRCH_FENCE: 1 + BIRCH_FENCE_GATE: 1 + BIRCH_WOOD_STAIRS: 1 + BLACK_GLAZED_TERRACOTTA: 1 + BLACK_SHULKER_BOX: 1 + BLUE_GLAZED_TERRACOTTA: 1 + BLUE_SHULKER_BOX: 1 + BOAT: 2 + BOAT_ACACIA: 2 + BOAT_BIRCH: 2 + BOAT_DARK_OAK: 2 + BOAT_JUNGLE: 2 + BOAT_SPRUCE: 2 + BONE_BLOCK: 1 + BOOKSHELF: 5 + BREWING_STAND: 20 + BRICK: 5 + BRICK_STAIRS: 5 + BROWN_GLAZED_TERRACOTTA: 1 + BROWN_SHULKER_BOX: 1 + BURNING_FURNACE: 10 + CACTUS: 1 + CAKE_BLOCK: 1 + CARPET: 1 + CAULDRON: 10 + CHEST: 2 + CHORUS_FLOWER: 1 + CHORUS_PLANT: 1 + CLAY: 2 + COAL_BLOCK: 9 + COAL_ORE: 0 + COBBLE_WALL: 1 + COBBLESTONE: 1 + COBBLESTONE_STAIRS: 1 + COCOA: 1 + CONCRETE: 1 + CONCRETE_POWDER: 1 + CYAN_GLAZED_TERRACOTTA: 1 + CYAN_SHULKER_BOX: 1 + DARK_OAK_DOOR: 1 + DARK_OAK_FENCE: 1 + DARK_OAK_FENCE_GATE: 1 + DARK_OAK_STAIRS: 1 + DAYLIGHT_DETECTOR: 10 + DAYLIGHT_DETECTOR_INVERTED: 10 + DEAD_BUSH: 1 + DETECTOR_RAIL: 10 + DIAMOND_BLOCK: 300 + DIODE: 5 + DIODE_BLOCK_OFF: 5 + DIODE_BLOCK_ON: 5 + DIRT: 2 + DISPENSER: 5 + DOUBLE_PLANT: 2 + DOUBLE_STEP: 1 + DOUBLE_STONE_SLAB2: 1 + DRAGON_EGG: 150 + DROPPER: 5 + EMERALD_BLOCK: 150 + EMERALD_ORE: 0 + ENCHANTMENT_TABLE: 150 + END_BRICKS: 2 + ENDER_CHEST: 150 + ENDER_PORTAL_FRAME: 0 + ENDER_PORTAL: 0 + ENDER_STONE: 2 + EXPLOSIVE_MINECART: 10 + FENCE: 1 + FENCE_GATE: 1 + FIRE: 0 + FLOWER_POT: 5 + FROSTED_ICE: 1 + FURNACE: 10 + GLASS: 2 + GLOWSTONE: 1 + GOLD_BLOCK: 150 + GOLD_ORE: 0 + GRASS: 5 + GRASS_PATH: 5 + GRAY_GLAZED_TERRACOTTA: 1 + GRAY_SHULKER_BOX: 1 + GRAVEL: 1 + GREEN_GLAZED_TERRACOTTA: 1 + GREEN_SHULKER_BOX: 1 + HARD_CLAY: 2 + HAY_BLOCK: 2 + HOPPER: 10 + HOPPER_MINECART: 20 + HUGE_MUSHROOM_1: 1 + HUGE_MUSHROOM_2: 1 + ICE: 5 + IRON_BLOCK: 10 + IRON_DOOR_BLOCK: 5 + IRON_FENCE: 5 + IRON_ORE: 0 + IRON_PLATE: 5 + IRON_TRAPDOOR: 1 + ITEM_FRAME: 2 + JACK_O_LANTERN: 1 + JUKEBOX: 10 + JUNGLE_DOOR: 1 + JUNGLE_FENCE: 1 + JUNGLE_FENCE_GATE: 1 + JUNGLE_WOOD_STAIRS: 1 + LADDER: 1 + LAPIS_BLOCK: 10 + LAPIS_ORE: 0 + LAVA: 0 + LEAVES_2: 1 + LEAVES: 1 + LEVER: 1 + LIGHT_BLUE_GLAZED_TERRACOTTA: 1 + LIGHT_BLUE_SHULKER_BOX: 1 + LIME_GLAZED_TERRACOTTA: 1 + LIME_SHULKER_BOX: 1 + LOG: 1 + #Other log types - examples + #LOG:3: 2 + LOG_2: 1 + LONG_GRASS: 1 + MAGENTA_GLAZED_TERRACOTTA: 1 + MAGENTA_SHULKER_BOX: 1 + MAGMA: 1 + MELON_BLOCK: 1 + MELON_STEM: 1 + MINECART: 10 + MOB_SPAWNER: 0 + MOSSY_COBBLESTONE: 2 + MYCEL: 5 + NETHER_BRICK: 2 + NETHER_BRICK_STAIRS: 2 + NETHER_FENCE: 2 + NETHER_STALK: 1 + NETHER_WART_BLOCK: 2 + NETHERRACK: 1 + NOTE_BLOCK: 10 + OBSERVER: 1 + OBSIDIAN: 10 + ORANGE_GLAZED_TERRACOTTA: 1 + ORANGE_SHULKER_BOX: 1 + PACKED_ICE: 5 + PAINTING: 2 + PINK_GLAZED_TERRACOTTA: 1 + PINK_SHULKER_BOX: 1 + PISTON_BASE: 2 + PISTON_STICKY_BASE: 2 + PORTAL: 0 + POWERED_MINECART: 10 + POWERED_RAIL: 10 + PRISMARINE: 10 + PUMPKIN_STEM: 1 + PUMPKIN: 1 + PURPLE_GLAZED_TERRACOTTA: 1 + PURPLE_SHULKER_BOX: 1 + PURPUR_BLOCK: 1 + PURPUR_DOUBLE_SLAB: 1 + PURPUR_PILLAR: 1 + PURPUR_SLAB: 1 + PURPUR_STAIRS: 1 + QUARTZ_BLOCK: 1 + QUARTZ_ORE: 0 + QUARTZ_STAIRS: 1 + QUARTZ: 1 + RAILS: 1 + RED_GLAZED_TERRACOTTA: 1 + RED_MUSHROOM: 1 + RED_NETHER_BRICK: 2 + RED_ROSE: 1 + RED_SANDSTONE: 1 + RED_SANDSTONE_STAIRS: 1 + RED_SHULKER_BOX: 1 + REDSTONE_BLOCK: 10 + REDSTONE_COMPARATOR_OFF: 10 + REDSTONE_COMPARATOR_ON: 10 + REDSTONE_COMPARATOR: 10 + REDSTONE_LAMP_OFF: 10 + REDSTONE_LAMP_ON: 10 + REDSTONE_ORE: 0 + REDSTONE_TORCH_OFF: 5 + REDSTONE_TORCH_ON: 5 + REDSTONE_WIRE: 1 + SAND: 1 + SANDSTONE: 1 + SANDSTONE_STAIRS: 1 + SEA_LANTERN: 1 + SIGN_POST: 1 + SILVER_GLAZED_TERRACOTTA: 1 + SILVER_SHULKER_BOX: 1 + SKULL: 10 + SLIME_BLOCK: 10 + SMOOTH_BRICK: 2 + SMOOTH_STAIRS: 2 + SNOW_BLOCK: 1 + SOIL: 2 + SOUL_SAND: 2 + SPONGE: 10 + SPRUCE_DOOR: 1 + SPRUCE_FENCE: 1 + SPRUCE_FENCE_GATE: 1 + SPRUCE_WOOD_STAIRS: 1 + STAINED_CLAY: 2 + STAINED_GLASS: 2 + STAINED_GLASS_PANE: 1 + STATIONARY_LAVA: 0 + STATIONARY_WATER: 0 + STEP: 1 + STONE: 1 + STONE_BUTTON: 1 + STONE_PLATE: 2 + STORAGE_MINECART: 10 + SUGAR_CANE_BLOCK: 1 + THIN_GLASS: 1 + TNT: 5 + TORCH: 2 + TRAP_DOOR: 5 + TRAPPED_CHEST: 10 + TRIPWIRE_HOOK: 2 + TRIPWIRE: 2 + VINE: 1 + WALL_SIGN: 1 + WATER_LILY: 5 + WEB: 10 + WHEAT: 1 + WHITE_GLAZED_TERRACOTTA: 1 + WHITE_SHULKER_BOX: 1 + WOOD: 1 + WOOD_BUTTON: 1 + WOOD_DOOR: 1 + WOOD_DOUBLE_STEP: 1 + WOOD_PLATE: 1 + WOOD_STAIRS: 1 + WOOD_STEP: 1 + WOODEN_DOOR: 1 + WOOL: 1 + WORKBENCH: 1 + YELLOW_FLOWER: 1 + YELLOW_GLAZED_TERRACOTTA: 1 + YELLOW_SHULKER_BOX: 1 + \ No newline at end of file diff --git a/locales/bsb_en_US.yml b/locales/bsb_en_US.yml new file mode 100755 index 0000000..7385cbf --- /dev/null +++ b/locales/bsb_en_US.yml @@ -0,0 +1,8 @@ +########################################################################################### +# This is a YML file. Be careful when editing. Check your edits in a YAML checker like # +# the one at http://yaml-online-parser.appspot.com # +########################################################################################### + +### Credits ### +# Tastybento: maintainer + diff --git a/plugin.yml b/plugin.yml new file mode 100755 index 0000000..74a9568 --- /dev/null +++ b/plugin.yml @@ -0,0 +1,22 @@ +name: BSkyBlock-Challenges +main: bskyblock.addin.challenges.Challenges +version: 0.1 + +authors: [tastybento] + +depend: [BSkyBlock] + +commands: + challenges: + description: Game challenges + aliases: [c, challenge] + usage: | + /challenges + +permissions: + bskyblock.island.challenges: + description: Let the player use the /challenges command + default: true + bskyblock.admin.challenges: + description: Access challenge admin commands + default: op diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..76f9908 --- /dev/null +++ b/pom.xml @@ -0,0 +1,63 @@ + + 4.0.0 + 0.0.1-SNAPSHOT + jar + + UTF-8 + + + src + clean package install + + + . + true + ${basedir} + + *.yml + + + + locales + false + ${basedir}/locales + + *.yml + + + + + + + maven-compiler-plugin + 3.5.1 + + 1.8 + 1.8 + + + + + + + org.spigotmc + spigot-api + 1.12-R0.1-SNAPSHOT + provided + + + us.tastybento + bskyblock + LATEST + + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + Challenges + bskyblock.addons + \ No newline at end of file diff --git a/src/bskyblock/addin/challenges/AddonHelper.java b/src/bskyblock/addin/challenges/AddonHelper.java new file mode 100644 index 0000000..c6394ed --- /dev/null +++ b/src/bskyblock/addin/challenges/AddonHelper.java @@ -0,0 +1,36 @@ +package bskyblock.addin.challenges; + +import java.util.logging.Logger; + +import org.bukkit.command.CommandSender; + +import us.tastybento.bskyblock.BSkyBlock; +import us.tastybento.bskyblock.config.BSBLocale; +import us.tastybento.bskyblock.util.Util; + +/** + * Makes code look nicer + * @author ben + * + */ +public abstract class AddonHelper { + protected final Challenges plugin; + protected final BSkyBlock bSkyBlock; + + public AddonHelper(Challenges plugin) { + this.plugin = plugin; + this.bSkyBlock = BSkyBlock.getPlugin(); + } + + public final Logger getLogger() { + return plugin.getLogger(); + } + + public final void sendMessage(CommandSender sender, String message) { + Util.sendMessage(sender, message); + } + + public final BSBLocale getLocale(CommandSender sender) { + return plugin.getLocale(sender); + } +} diff --git a/src/bskyblock/addin/challenges/Challenges.java b/src/bskyblock/addin/challenges/Challenges.java new file mode 100644 index 0000000..2128a64 --- /dev/null +++ b/src/bskyblock/addin/challenges/Challenges.java @@ -0,0 +1,94 @@ +package bskyblock.addin.challenges; + +import java.util.UUID; + +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; + +import bskyblock.addin.challenges.commands.ChallengesCommand; +import bskyblock.addin.challenges.config.LocaleManager; +import bskyblock.addin.challenges.config.PluginConfig; +import us.tastybento.bskyblock.BSkyBlock; +import us.tastybento.bskyblock.config.BSBLocale; +import us.tastybento.bskyblock.database.BSBDatabase; +import us.tastybento.bskyblock.database.flatfile.FlatFileDatabase; + +/** + * Addin to BSkyBlock that enables challenges + * @author tastybento + * + */ +public class Challenges extends JavaPlugin { + + + private static final boolean DEBUG = true; + + // The BSkyBlock plugin instance. + private BSkyBlock bSkyBlock; + + // Locale manager for this plugin + private LocaleManager localeManager; + + // The BSkyBlock database object + private BSBDatabase database; + + private ChallengesManager manager; + + private FlatFileDatabase flatFile; + + + @SuppressWarnings("unchecked") + @Override + public void onEnable() { + // Load the plugin's config + new PluginConfig(this); + // Get the BSkyBlock plugin. This will be available because this plugin depends on it in plugin.yml. + bSkyBlock = BSkyBlock.getPlugin(); + // Check if it is enabled - it might be loaded, but not enabled. + if (bSkyBlock == null || !bSkyBlock.isEnabled()) { + this.setEnabled(false); + return; + } + + // Local locales + localeManager = new LocaleManager(this); + + // Challenges Manager + manager = new ChallengesManager(this); + // Register commands + new ChallengesCommand(this); + // Register Listener + getServer().getPluginManager().registerEvents(manager, this); + // Done + } + + @Override + public void onDisable(){ + if (manager != null) + manager.save(false); + } + + + /** + * Get the locale for this player + * @param sender + * @return Locale object for sender + */ + public BSBLocale getLocale(CommandSender sender) { + return localeManager.getLocale(sender); + } + + /** + * Get the locale for this UUID + * @param uuid + * @return Locale object for UUID + */ + public BSBLocale getLocale(UUID uuid) { + return localeManager.getLocale(uuid); + } + + public ChallengesManager getManager() { + return manager; + } + +} diff --git a/src/bskyblock/addin/challenges/ChallengesManager.java b/src/bskyblock/addin/challenges/ChallengesManager.java new file mode 100644 index 0000000..54869c5 --- /dev/null +++ b/src/bskyblock/addin/challenges/ChallengesManager.java @@ -0,0 +1,257 @@ +package bskyblock.addin.challenges; + +import java.beans.IntrospectionException; +import java.lang.reflect.InvocationTargetException; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.inventory.ClickType; +import org.bukkit.event.inventory.InventoryClickEvent; +import org.bukkit.event.inventory.InventoryCloseEvent; +import org.bukkit.event.inventory.InventoryOpenEvent; +import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +import bskyblock.addin.challenges.database.object.ChallengesDO; +import bskyblock.addin.challenges.database.object.LevelsDO; +import bskyblock.addin.challenges.panel.Panel; +import bskyblock.addin.challenges.panel.Panel.PanelBuilder; +import bskyblock.addin.challenges.panel.Panel.PanelItem; +import us.tastybento.bskyblock.database.flatfile.FlatFileDatabase; +import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler; +import us.tastybento.bskyblock.util.Util; + +public class ChallengesManager implements Listener { + + private static final boolean DEBUG = false; + private Challenges plugin; + private HashMap challengePanels; + + private AbstractDatabaseHandler chHandler; + private HashMap challenges; + private AbstractDatabaseHandler lvHandler; + private HashMap levels; + + @SuppressWarnings("unchecked") + public ChallengesManager(Challenges plugin){ + this.plugin = plugin; + // Set up the database handler to store and retrieve Challenges + chHandler = (AbstractDatabaseHandler) new FlatFileDatabase().getHandler(plugin, ChallengesDO.class); + lvHandler = (AbstractDatabaseHandler) new FlatFileDatabase().getHandler(plugin, LevelsDO.class); + challenges = new HashMap<>(); + levels = new HashMap<>(); + challengePanels = new HashMap<>(); + load(); + } + + public AbstractDatabaseHandler getHandler() { + return chHandler; + } + + /** + * Clear and reload all challenges + */ + public void load() { + levels.clear(); + try { + for (LevelsDO level : lvHandler.loadObjects()) { + levels.put(level.getUniqueId(), level); + } + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | SecurityException | ClassNotFoundException | IntrospectionException + | SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + challenges.clear(); + try { + for (ChallengesDO challenge : chHandler.loadObjects()) { + challenges.put(challenge.getUniqueId(), challenge); + } + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException + | InvocationTargetException | SecurityException | ClassNotFoundException | IntrospectionException + | SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * Save to the database + * @param async - if true, saving will be done async + */ + public void save(boolean async){ + if(async){ + Runnable save = () -> { + int index = 1; + for(ChallengesDO challenge : challenges.values()){ + plugin.getLogger().info("DEBUG: saving challenges async " + index++); + try { + chHandler.saveObject(challenge); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + plugin.getServer().getScheduler().runTaskAsynchronously(plugin, save); + } else { + int index = 1; + for(ChallengesDO challenge : challenges.values()){ + plugin.getLogger().info("DEBUG: saving challenges sync " + index++); + try { + chHandler.saveObject(challenge); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + // Metrics-related methods // + + public void shutdown(){ + save(false); + challenges.clear(); + } + + /** + * Create a challenge from the inventory contents + * @param contents + */ + public void createChallenge(Player player, String name) { + // Get the main icon + ItemStack icon = player.getInventory().getItemInOffHand(); + if (icon == null || icon.getType().equals(Material.AIR)) { + Util.sendMessage(player, "Icon will be paper"); + icon = new ItemStack(Material.PAPER); + } + icon.setAmount(1); + ItemMeta meta = icon.getItemMeta(); + meta.setDisplayName(name); + List lore = new ArrayList<>(); + lore.add("Required items:"); + + List inv = Arrays.asList(player.getInventory().getStorageContents()); + List contents = new ArrayList<>(); + for (ItemStack item : inv) { + if (item != null && !item.getType().equals(Material.AIR)) { + contents.add(item); + lore.add(item.getType() + " x " + item.getAmount()); + } + } + if (lore.size() == 1) { + lore.add("No items"); + } + meta.setDisplayName(name); + meta.setLore(lore); + icon.setItemMeta(meta); + ChallengesDO newChallenge = new ChallengesDO(); + newChallenge.setRequiredItems(contents); + newChallenge.setUniqueId(name); + newChallenge.setIcon(icon); + if (chHandler.objectExits(name)) { + Util.sendMessage(player, ChatColor.RED + "Challenge already exists! Use /c replace "); + return; + } + try { + chHandler.saveObject(newChallenge); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException + | InstantiationException | NoSuchMethodException | IntrospectionException | SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + Util.sendMessage(player, ChatColor.RED + "Challenge creation failed! " + e.getMessage()); + return; + } + Util.sendMessage(player, "Challenge accepted!"); + challenges.put(newChallenge.getUniqueId(), newChallenge); + } + + public Inventory getChallenges(Player player) { + // TODO build the panel that is customized to the player + // Build panel + PanelBuilder panelBuilder = Panel.builder(plugin) + .name(plugin.getLocale(player).get("challenges.guiTitle")); + for (ChallengesDO challenge: challenges.values()) { + plugin.getLogger().info("Adding challenge " + challenge.getUniqueId()); + PanelItem item = Panel.panelItemBuilder() + .setIcon(challenge.getIcon()) + .setName(challenge.getFriendlyName().isEmpty() ? challenge.getUniqueId() : challenge.getFriendlyName()) + .setDescription(challenge.getDescription()) + .setSlot(challenge.getSlot()) + .build(); + plugin.getLogger().info("requested slot" + item.getSlot()); + panelBuilder.addItem(item); + } + Panel panel = panelBuilder.build(); + challengePanels.put(player.getUniqueId(), panel); + plugin.getLogger().info("DEBUG: added inv " + challengePanels.size()); + return panel.getPanel(); + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onInventoryClick(InventoryClickEvent event) { + Player player = (Player) event.getWhoClicked(); // The player that + // clicked the item + UUID playerUUID = player.getUniqueId(); + Inventory inventory = event.getInventory(); // The inventory that was + // clicked in + // Check this is the right panel + if (inventory.getName() == null || !inventory.getName().equals(plugin.getLocale(player).get("challenges.guiTitle"))) { + return; + } + event.setCancelled(true); + if (!event.getClick().equals(ClickType.LEFT)) { + inventory.clear(); + player.closeInventory(); + player.updateInventory(); + return; + } + int slot = event.getRawSlot(); + if (slot == -999) { + inventory.clear(); + player.closeInventory(); + event.setCancelled(true); + return; + } + // TODO: Deal with the clicking + } + + @EventHandler(priority = EventPriority.LOWEST) + public void onInventoryClose(InventoryCloseEvent event) { + challengePanels.remove(event.getPlayer().getUniqueId()); + plugin.getLogger().info("DEBUG: removing inv " + challengePanels.size()); + } + + /** + * Clean up the hashmap should the player open up another inventory + * @param event + */ + @EventHandler(priority = EventPriority.LOWEST) + public void onInventoryOpen(InventoryOpenEvent event) { + Player player = (Player) event.getPlayer(); + UUID playerUUID = player.getUniqueId(); + Inventory inventory = event.getInventory(); // The inventory that was + if (inventory.getName() == null || !inventory.getName().equals(plugin.getLocale(player).get("challenges.guiTitle"))) { + challengePanels.remove(playerUUID); + plugin.getLogger().info("DEBUG: removing inv " + challengePanels.size()); + } + } + + @EventHandler(priority = EventPriority.NORMAL) + public void onLogOut(PlayerQuitEvent event) { + challengePanels.remove(event.getPlayer().getUniqueId()); + plugin.getLogger().info("DEBUG: removing inv " + challengePanels.size()); + } +} diff --git a/src/bskyblock/addin/challenges/commands/ChallengesCommand.java b/src/bskyblock/addin/challenges/commands/ChallengesCommand.java new file mode 100644 index 0000000..3b2e537 --- /dev/null +++ b/src/bskyblock/addin/challenges/commands/ChallengesCommand.java @@ -0,0 +1,86 @@ +package bskyblock.addin.challenges.commands; + +import java.util.Set; +import java.util.UUID; + +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; + +import bskyblock.addin.challenges.Challenges; +import us.tastybento.bskyblock.api.commands.AbstractCommand; +import us.tastybento.bskyblock.api.commands.ArgumentHandler; +import us.tastybento.bskyblock.api.commands.CanUseResp; +import us.tastybento.bskyblock.config.Settings; +import us.tastybento.bskyblock.util.VaultHelper; + +public class ChallengesCommand extends AbstractCommand implements Listener { + private static final String CHALLENGE_COMMAND = "challenges"; + private Challenges plugin; + + public ChallengesCommand(Challenges plugin) { + super(CHALLENGE_COMMAND, new String[]{"c", "challenge"}, true); + plugin.getCommand(CHALLENGE_COMMAND).setExecutor(this); + plugin.getCommand(CHALLENGE_COMMAND).setTabCompleter(this); + this.plugin = plugin; + } + + @Override + public CanUseResp canUse(CommandSender sender) { + if (!(sender instanceof Player)) { + return new CanUseResp(getLocale(sender).get("general.errors.use-in-game")); + } + + // Basic permission check to use /challenges + if (!VaultHelper.hasPerm(player, Settings.PERMPREFIX + "island.challenges")) { + return new CanUseResp(getLocale(sender).get("general.errors.no-permission")); + } + + return new CanUseResp(true); + } + + @Override + public void execute(CommandSender sender, String[] args) { + // Open up the challenges GUI + if (isPlayer) { + player.openInventory(plugin.getManager().getChallenges(player)); + } else { + // TODO + } + } + + @Override + public void setup() { + addArgument(new ArgumentHandler(label) { + + @Override + public CanUseResp canUse(CommandSender sender) { + return new CanUseResp(true); + } + + @Override + public void execute(CommandSender sender, String[] args) { + // Create a copy of items in the player's main inventory + Player player = (Player)sender; + String name = UUID.randomUUID().toString(); + if (args.length > 0) { + name = args[0]; + } + plugin.getManager().createChallenge(player, name); + } + + @Override + public Set tabComplete(CommandSender sender, String[] args) { + return null; + } + + @Override + public String[] usage(CommandSender sender) { + return new String[] {null, "Make a challenge from the items in your inventory"}; + } + }.alias("make")); + + } + + +} diff --git a/src/bskyblock/addin/challenges/config/LocaleManager.java b/src/bskyblock/addin/challenges/config/LocaleManager.java new file mode 100644 index 0000000..a8e9f5f --- /dev/null +++ b/src/bskyblock/addin/challenges/config/LocaleManager.java @@ -0,0 +1,28 @@ +package bskyblock.addin.challenges.config; + +import java.util.UUID; + +import bskyblock.addin.challenges.Challenges; +import us.tastybento.bskyblock.BSkyBlock; +import us.tastybento.bskyblock.config.AbstractLocaleManager; +import us.tastybento.bskyblock.config.BSBLocale; +import us.tastybento.bskyblock.config.Settings; + +public class LocaleManager extends AbstractLocaleManager { + + public LocaleManager(Challenges plugin) { + super(plugin); + } + + @Override + public BSBLocale getLocale(UUID player) { + //getLogger().info("DEBUG: " + player); + //getLogger().info("DEBUG: " + getPlayers() == null ? "Players is null":"Players in not null"); + //getLogger().info("DEBUG: " + getPlayers().getPlayer(player)); + //getLogger().info("DEBUG: " + getPlayers().getPlayer(player).getLocale()); + String locale = BSkyBlock.getPlugin().getPlayers().getPlayer(player).getLocale(); + if(locale.isEmpty() || !getLocales().containsKey(locale)) return getLocales().get(Settings.defaultLanguage); + + return getLocales().get(locale); + } +} diff --git a/src/bskyblock/addin/challenges/config/PluginConfig.java b/src/bskyblock/addin/challenges/config/PluginConfig.java new file mode 100644 index 0000000..009e3f8 --- /dev/null +++ b/src/bskyblock/addin/challenges/config/PluginConfig.java @@ -0,0 +1,95 @@ +package bskyblock.addin.challenges.config; + +import java.util.HashMap; + +import org.apache.commons.lang.StringUtils; +import org.bukkit.Material; +import org.bukkit.material.MaterialData; + +import bskyblock.addin.challenges.Challenges; + +public class PluginConfig { + private static final boolean DEBUG = false; + + /** + * Loads the various settings from the config.yml file into the plugin + */ + public PluginConfig(Challenges plugin) { + plugin.saveDefaultConfig(); + + // Island level cool down time + Settings.levelWait = plugin.getConfig().getInt("levelwait", 60); + if (Settings.levelWait < 0) { + Settings.levelWait = 0; + } + + // Get the under water multiplier + Settings.deathpenalty = plugin.getConfig().getInt("deathpenalty", 0); + Settings.sumTeamDeaths = plugin.getConfig().getBoolean("sumteamdeaths"); + Settings.maxDeaths = plugin.getConfig().getInt("maxdeaths", 10); + Settings.islandResetDeathReset = plugin.getConfig().getBoolean("islandresetdeathreset", true); + Settings.teamJoinDeathReset = plugin.getConfig().getBoolean("teamjoindeathreset", true); + Settings.underWaterMultiplier = plugin.getConfig().getDouble("underwater", 1D); + Settings.levelCost = plugin.getConfig().getInt("levelcost", 100); + if (Settings.levelCost < 1) { + Settings.levelCost = 1; + plugin.getLogger().warning("levelcost in blockvalues.yml cannot be less than 1. Setting to 1."); + } + Settings.blockLimits = new HashMap(); + if (plugin.getConfig().isSet("limits")) { + for (String material : plugin.getConfig().getConfigurationSection("limits").getKeys(false)) { + try { + String[] split = material.split(":"); + byte data = 0; + if (split.length>1) { + data = Byte.valueOf(split[1]); + } + Material mat; + if (StringUtils.isNumeric(split[0])) { + mat = Material.getMaterial(Integer.parseInt(split[0])); + } else { + mat = Material.valueOf(split[0].toUpperCase()); + } + MaterialData materialData = new MaterialData(mat); + materialData.setData(data); + Settings.blockLimits.put(materialData, plugin.getConfig().getInt("limits." + material, 0)); + if (DEBUG) { + plugin.getLogger().info("Maximum number of " + materialData + " will be " + Settings.blockLimits.get(materialData)); + } + } catch (Exception e) { + plugin.getLogger().warning("Unknown material (" + material + ") in blockvalues.yml Limits section. Skipping..."); + } + } + } + Settings.blockValues = new HashMap(); + if (plugin.getConfig().isSet("blocks")) { + for (String material : plugin.getConfig().getConfigurationSection("blocks").getKeys(false)) { + try { + String[] split = material.split(":"); + byte data = 0; + if (split.length>1) { + data = Byte.valueOf(split[1]); + } + MaterialData materialData = null; + if (StringUtils.isNumeric(split[0])) { + materialData = new MaterialData(Integer.parseInt(split[0])); + } else { + materialData = new MaterialData(Material.valueOf(split[0].toUpperCase())); + } + + materialData.setData(data); + Settings.blockValues.put(materialData, plugin.getConfig().getInt("blocks." + material, 0)); + if (DEBUG) { + plugin.getLogger().info(materialData.toString() + " value = " + Settings.blockValues.get(materialData)); + } + } catch (Exception e) { + // e.printStackTrace(); + plugin.getLogger().warning("Unknown material (" + material + ") in blockvalues.yml blocks section. Skipping..."); + } + } + } else { + plugin.getLogger().severe("No block values in blockvalues.yml! All island levels will be zero!"); + } + // All done + } +} diff --git a/src/bskyblock/addin/challenges/config/Settings.java b/src/bskyblock/addin/challenges/config/Settings.java new file mode 100644 index 0000000..c9d5023 --- /dev/null +++ b/src/bskyblock/addin/challenges/config/Settings.java @@ -0,0 +1,22 @@ +package bskyblock.addin.challenges.config; + +import java.util.HashMap; + +import org.bukkit.material.MaterialData; + +public class Settings { + + public static boolean sumTeamDeaths; + public static int seaHeight; + public static HashMap blockLimits; + public static HashMap blockValues; + public static double underWaterMultiplier; + public static int deathpenalty; + public static long levelCost; + public static Object defaultLanguage; + public static int levelWait; + public static int maxDeaths; + public static boolean islandResetDeathReset; + public static boolean teamJoinDeathReset; + +} diff --git a/src/bskyblock/addin/challenges/database/object/ChallengesDO.java b/src/bskyblock/addin/challenges/database/object/ChallengesDO.java new file mode 100644 index 0000000..8072c13 --- /dev/null +++ b/src/bskyblock/addin/challenges/database/object/ChallengesDO.java @@ -0,0 +1,401 @@ +package bskyblock.addin.challenges.database.object; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; + +import us.tastybento.bskyblock.database.objects.DataObject; + +public class ChallengesDO extends DataObject { + + enum ChallengeType { + /** + * This challenge only shows and icon in the GUI and doesn't do anything. + */ + ICON, + /** + * The player must have the items on them. + */ + INVENTORY, + /** + * The island level has to be equal or over this amount. Only works if there's an island level plugin installed. + */ + LEVEL, + /** + * Items or required entities have to be within x blocks of the player. + */ + SURROUNDING + } + + /** + * Type of challenge + */ + private ChallengeType challengeType; + /** + * Whether this challenge is deployed or not + */ + private boolean deployed; + /** + * Description of the challenge. Will become the lore on the icon. Can include color codes. + */ + private String description = ""; + /** + * Experience point reward + */ + private long expReward; + /** + * This challenge can be completed at any time + */ + private boolean freeChallenge; + /** + * Name of the icon and challenge. May include color codes. + */ + private String friendlyName = ""; + /** + * The icon in the GUI for this challenge + */ + private ItemStack icon = new ItemStack(Material.PAPER); + /** + * The challenge level, e.g. Novice, Expert, etc. + * Levels are completed in order + */ + private String level = "Novice"; + /** + * Maximum number of times the challenge can be repeated + */ + private long maxTimes = 1; + /** + * Money reward + */ + private long moneyReward; + /** + * If true, the challenge will disappear from the GUI when completed + */ + private boolean removeWhenCompleted; + /** + * True if the challenge is repeatable + */ + private boolean repeatable; + /** + * Repeat exp award + */ + private long repeatExpReward; + /** + * Reward items for repeating the challenge + */ + private List repeatItemReward = new ArrayList<>(); + /** + * Repeat money award + */ + private long repeatMoneyReward; + /** + * Commands to run when challenge is repeated + */ + private List repeatrewardcommands = new ArrayList<>(); + /** + * Description of the repeat rewards. If blank, it will be autogenerated. + */ + private String repeatRewardText = ""; + /** + * Minimum amount of player experience + */ + private long reqExp; + /** + * Require level for this challenge. + */ + private long reqIslandlevel; + /** + * Minimum amount of money required + */ + private long reqMoney; + /** + * The required permissions to see this challenge + */ + private Set reqPerms = new HashSet<>(); + /** + * The items that must be in the inventory to complete the challenge. + */ + private List requiredItems = new ArrayList<>(); + /** + * Commands to run when the player completes the challenge for the first time + */ + private List rewardCommands = new ArrayList<>(); + /** + * List of items the player will receive first time + */ + private List rewardItems = new ArrayList<>(); + /** + * If this is blank, the reward text will be auto-generated, otherwise this will be used. + */ + private String rewardText = ""; + /** + * The number of blocks around the player to search for items on an island + */ + private int searchRadius = 10; + /** + * Inventory slot where this challenge should be placed. 0 to 49. + * + */ + private int slot; + /** + * Take the required items from the player + */ + private boolean takeItems = true; + /** + * Take the money from the player + */ + private boolean takeMoney = false; + + /** + * Unique name of the challenge + */ + private String uniqueId = ""; + + public ChallengeType getChallengeType() { + return challengeType; + } + + public String getDescription() { + return description; + } + + public long getExpReward() { + return expReward; + } + + public String getFriendlyName() { + return friendlyName; + } + + public ItemStack getIcon() { + return icon; + } + + public String getLevel() { + return level; + } + + public long getMaxTimes() { + return maxTimes; + } + + public long getMoneyReward() { + return moneyReward; + } + + public long getRepeatExpReward() { + return repeatExpReward; + } + + public List getRepeatItemReward() { + return repeatItemReward; + } + + public long getRepeatMoneyReward() { + return repeatMoneyReward; + } + + public List getRepeatrewardcommands() { + return repeatrewardcommands; + } + + public String getRepeatRewardText() { + return repeatRewardText; + } + + public long getReqExp() { + return reqExp; + } + + public long getReqIslandlevel() { + return reqIslandlevel; + } + + public long getReqMoney() { + return reqMoney; + } + + public Set getReqPerms() { + return reqPerms; + } + + public List getRequiredItems() { + return requiredItems; + } + + public List getRewardCommands() { + return rewardCommands; + } + + public List getRewardItems() { + return rewardItems; + } + + public String getRewardText() { + return rewardText; + } + + public int getSearchRadius() { + return searchRadius; + } + + public int getSlot() { + return slot; + } + + @Override + public String getUniqueId() { + return uniqueId; + } + + public boolean isDeployed() { + return deployed; + } + + public boolean isFreeChallenge() { + return freeChallenge; + } + + public boolean isRemoveWhenCompleted() { + return removeWhenCompleted; + } + + public boolean isRepeatable() { + return repeatable; + } + + public boolean isTakeItems() { + return takeItems; + } + + public boolean isTakeMoney() { + return takeMoney; + } + + public void setChallengeType(ChallengeType challengeType) { + this.challengeType = challengeType; + } + + public void setDeployed(boolean deployed) { + this.deployed = deployed; + } + + public void setDescription(String description) { + this.description = description; + } + + public void setExpReward(long expReward) { + this.expReward = expReward; + } + + public void setFreeChallenge(boolean freeChallenge) { + this.freeChallenge = freeChallenge; + } + + public void setFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + } + + public void setIcon(ItemStack icon) { + this.icon = icon; + } + + public void setLevel(String level) { + this.level = level; + } + + public void setMaxTimes(long maxTimes) { + this.maxTimes = maxTimes; + } + + public void setMoneyReward(long moneyReward) { + this.moneyReward = moneyReward; + } + + public void setRemoveWhenCompleted(boolean removeWhenCompleted) { + this.removeWhenCompleted = removeWhenCompleted; + } + + public void setRepeatable(boolean repeatable) { + this.repeatable = repeatable; + } + + public void setRepeatExpReward(long repeatExpReward) { + this.repeatExpReward = repeatExpReward; + } + + public void setRepeatItemReward(List repeatItemReward) { + this.repeatItemReward = repeatItemReward; + } + + public void setRepeatMoneyReward(long repeatMoneyReward) { + this.repeatMoneyReward = repeatMoneyReward; + } + + public void setRepeatrewardcommands(List repeatrewardcommands) { + this.repeatrewardcommands = repeatrewardcommands; + } + + public void setRepeatRewardText(String repeatRewardText) { + this.repeatRewardText = repeatRewardText; + } + + public void setReqExp(long reqExp) { + this.reqExp = reqExp; + } + + public void setReqIslandlevel(long reqIslandlevel) { + this.reqIslandlevel = reqIslandlevel; + } + + public void setReqMoney(long reqMoney) { + this.reqMoney = reqMoney; + } + + public void setReqPerms(Set reqPerms) { + this.reqPerms = reqPerms; + } + + public void setRequiredItems(List requiredItems) { + this.requiredItems = requiredItems; + } + + public void setRewardCommands(List rewardCommands) { + this.rewardCommands = rewardCommands; + } + + public void setRewardItems(List rewardItems) { + this.rewardItems = rewardItems; + } + + public void setRewardText(String rewardText) { + this.rewardText = rewardText; + } + + public void setSearchRadius(int searchRadius) { + this.searchRadius = searchRadius; + } + + public void setSlot(int slot) { + this.slot = slot; + } + + public void setTakeItems(boolean takeItems) { + this.takeItems = takeItems; + } + + public void setTakeMoney(boolean takeMoney) { + this.takeMoney = takeMoney; + } + + @Override + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + +} diff --git a/src/bskyblock/addin/challenges/database/object/LevelsDO.java b/src/bskyblock/addin/challenges/database/object/LevelsDO.java new file mode 100644 index 0000000..6d28d2a --- /dev/null +++ b/src/bskyblock/addin/challenges/database/object/LevelsDO.java @@ -0,0 +1,61 @@ +package bskyblock.addin.challenges.database.object; + +import java.util.ArrayList; +import java.util.List; + +import us.tastybento.bskyblock.database.objects.DataObject; + +public class LevelsDO extends DataObject { + + /** + * A friendly name for the level. If blank, level name is used. + */ + private String friendlyName = ""; + /** + * Commands to run when this level is completed + */ + private List rewardCommands = new ArrayList<>(); + /** + * Level name + */ + private String uniqueId = ""; + /** + * The number of undone challenges that can be left on this level before unlocking next level + */ + private int waiveramount = 1; + + public String getFriendlyName() { + return friendlyName; + } + + public List getRewardCommands() { + return rewardCommands; + } + + @Override + public String getUniqueId() { + return uniqueId; + } + + public int getWaiveramount() { + return waiveramount; + } + + public void setFriendlyName(String friendlyName) { + this.friendlyName = friendlyName; + } + + public void setRewardCommands(List rewardCommands) { + this.rewardCommands = rewardCommands; + } + + @Override + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public void setWaiveramount(int waiveramount) { + this.waiveramount = waiveramount; + } + +} diff --git a/src/bskyblock/addin/challenges/panel/Panel.java b/src/bskyblock/addin/challenges/panel/Panel.java new file mode 100644 index 0000000..98ac4da --- /dev/null +++ b/src/bskyblock/addin/challenges/panel/Panel.java @@ -0,0 +1,202 @@ +package bskyblock.addin.challenges.panel; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map.Entry; +import java.util.TreeMap; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.enchantments.Enchantment; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemFlag; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.plugin.Plugin; + +public class Panel { + + private final Inventory gui; + private final TreeMap panelItems; + + public Panel(Plugin plugin, String name, TreeMap panelItems) { + // Generate gui + this.panelItems = panelItems; + // Create the panel + if (panelItems.lastKey() > 0) { + // Make sure size is a multiple of 9 + int size = panelItems.lastKey() + 8; + size -= (size % 9); + gui = Bukkit.createInventory(null, size, name); + // Fill the inventory and return + for (Entry en: panelItems.entrySet()) { + gui.setItem(en.getKey(), en.getValue().getIcon()); + } + } else { + gui = Bukkit.createInventory(null, 9, name); + } + + } + + public TreeMap getPanelItems() { + return panelItems; + } + + public Inventory getPanel() { + return gui; + } + + public static PanelBuilder builder(Plugin plugin) { + return new PanelBuilder(plugin); + } + + public static class PanelBuilder { + private TreeMap panelItems = new TreeMap<>(); + private String name; + private Plugin plugin; + + public PanelBuilder(Plugin plugin) { + this.plugin = plugin; + } + + public PanelBuilder addItem(PanelItem item) { + // Fit into slots. Handle duplicates + int index = item.getSlot(); + while (panelItems.containsKey(index) || index == 49) { + index++; + }; + panelItems.put(index, item); + Bukkit.getLogger().info("DEBUG: added to slot " + index); + return this; + } + + public PanelBuilder name(String name) { + this.name = name; + return this; + } + + public Panel build() { + return new Panel(plugin, name, panelItems); + } + + } + + public static PanelItemBuilder panelItemBuilder() { + return new PanelItemBuilder(); + } + + public static class PanelItem { + private final Integer slot; + // The current index of the icon + private int index = 0; + // There is a list of icons for every toggle option + private final List icon; + + public PanelItem(ItemStack icon, String description, String name, Integer slot, List toggleItems, boolean glow) { + this.slot = slot; + List result = new ArrayList<>(); + if (toggleItems.isEmpty()) { + // Create the icon + ItemMeta meta = icon.getItemMeta(); + meta.setDisplayName(name); + meta.setLore(chop(description)); + // Set flags to neaten up the view + meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); + meta.addItemFlags(ItemFlag.HIDE_DESTROYS); + meta.addItemFlags(ItemFlag.HIDE_PLACED_ON); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + if (glow) { + meta.addEnchant(Enchantment.ARROW_DAMAGE, 0, true); + } + icon.setItemMeta(meta); + result.add(icon); + } else { + for (int i = 0; i < toggleItems.size(); i++) { + // Create the icon(s) + ItemMeta meta = icon.getItemMeta(); + meta.setDisplayName(name); + List desc = chop(description); + desc.addAll(chop(toggleItems.get(i))); + meta.setLore(desc); + // Set flags to neaten up the view + meta.addItemFlags(ItemFlag.HIDE_ATTRIBUTES); + meta.addItemFlags(ItemFlag.HIDE_DESTROYS); + meta.addItemFlags(ItemFlag.HIDE_PLACED_ON); + meta.addItemFlags(ItemFlag.HIDE_ENCHANTS); + if (glow) { + meta.addEnchant(Enchantment.ARROW_DAMAGE, 0, true); + } + icon.setItemMeta(meta); + result.add(icon); + } + } + this.icon = result; + } + + public ItemStack getIcon() { + return icon.get(index); + } + + public ItemStack toggleIcon() { + if (icon.size() < (index + 1)) { + index++; + } else { + index = 0; + } + return icon.get(index); + } + + public Integer getSlot() { + return slot; + } + + } + + public static class PanelItemBuilder { + private ItemStack icon; + private String description; + private String name; + private Integer slot; + private List toggleItems = new ArrayList<>(); + private boolean glow; + + public PanelItemBuilder setIcon(ItemStack icon) { + this.icon = icon; + return this; + } + public PanelItemBuilder setDescription(String description) { + this.description = description; + return this; + } + public PanelItemBuilder setName(String name) { + this.name = name; + return this; + } + public PanelItemBuilder setSlot(Integer slot) { + this.slot = slot; + return this; + } + public PanelItemBuilder setToggleItems(List toggleItems) { + this.toggleItems = toggleItems; + return this; + } + public PanelItemBuilder setGlow(boolean glow) { + this.glow = glow; + return this; + } + public PanelItem build() { + return new PanelItem(icon, description, name, slot, toggleItems, glow); + } + + + } + + private static List chop(String longLine) { + longLine = ChatColor.translateAlternateColorCodes('&', longLine); + // Split pip character requires escaping it + String[] split = longLine.split("\\|"); + return new ArrayList(Arrays.asList(split)); + } + +} \ No newline at end of file