From 3e6507a654cff06ae4680d5c63b8466d3d66aad7 Mon Sep 17 00:00:00 2001 From: tastybento Date: Wed, 25 Oct 2017 18:33:23 -0700 Subject: [PATCH] Initial commit --- WelcomeWarps/config.yml | 305 ++++++++++++ WelcomeWarps/locales/bsb_en_US.yml | 29 ++ WelcomeWarps/plugin.yml | 7 + WelcomeWarps/pom.xml | 63 +++ .../bskyblock/addin/warps/AddonHelper.java | 36 ++ .../src/bskyblock/addin/warps/CPItem.java | 117 +++++ .../src/bskyblock/addin/warps/Warp.java | 96 ++++ .../src/bskyblock/addin/warps/WarpPanel.java | 299 ++++++++++++ .../src/bskyblock/addin/warps/WarpSigns.java | 440 ++++++++++++++++++ .../addin/warps/commands/Commands.java | 270 +++++++++++ .../addin/warps/config/LocaleManager.java | 28 ++ .../addin/warps/config/PluginConfig.java | 95 ++++ .../addin/warps/config/Settings.java | 23 + .../addin/warps/database/object/Warps.java | 38 ++ .../addin/warps/event/WarpCreateEvent.java | 54 +++ .../addin/warps/event/WarpListEvent.java | 75 +++ .../addin/warps/event/WarpRemoveEvent.java | 54 +++ 17 files changed, 2029 insertions(+) create mode 100644 WelcomeWarps/config.yml create mode 100755 WelcomeWarps/locales/bsb_en_US.yml create mode 100755 WelcomeWarps/plugin.yml create mode 100644 WelcomeWarps/pom.xml create mode 100644 WelcomeWarps/src/bskyblock/addin/warps/AddonHelper.java create mode 100644 WelcomeWarps/src/bskyblock/addin/warps/CPItem.java create mode 100644 WelcomeWarps/src/bskyblock/addin/warps/Warp.java create mode 100644 WelcomeWarps/src/bskyblock/addin/warps/WarpPanel.java create mode 100644 WelcomeWarps/src/bskyblock/addin/warps/WarpSigns.java create mode 100644 WelcomeWarps/src/bskyblock/addin/warps/commands/Commands.java create mode 100644 WelcomeWarps/src/bskyblock/addin/warps/config/LocaleManager.java create mode 100644 WelcomeWarps/src/bskyblock/addin/warps/config/PluginConfig.java create mode 100644 WelcomeWarps/src/bskyblock/addin/warps/config/Settings.java create mode 100644 WelcomeWarps/src/bskyblock/addin/warps/database/object/Warps.java create mode 100644 WelcomeWarps/src/bskyblock/addin/warps/event/WarpCreateEvent.java create mode 100644 WelcomeWarps/src/bskyblock/addin/warps/event/WarpListEvent.java create mode 100644 WelcomeWarps/src/bskyblock/addin/warps/event/WarpRemoveEvent.java diff --git a/WelcomeWarps/config.yml b/WelcomeWarps/config.yml new file mode 100644 index 0000000..15b3707 --- /dev/null +++ b/WelcomeWarps/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/WelcomeWarps/locales/bsb_en_US.yml b/WelcomeWarps/locales/bsb_en_US.yml new file mode 100755 index 0000000..9e9a68d --- /dev/null +++ b/WelcomeWarps/locales/bsb_en_US.yml @@ -0,0 +1,29 @@ +########################################################################################### +# 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 +# Poslovitch: maintainer +# +# This translation is adapted to version : [alpha-0.0.1] + +warps: + welcomeLine: "[Welcome]" + removed: "Warp sign removed" + success: "Success!" + sign-removed: "Warp sign removed!" + title: "Warp Signs" + previous: "Previous page" + next: "Next page" + warpToPlayersSign: "Warping to [player]'s sign" + warpTip: "Place a warp sign with [Welcome] on the top" + error: + no-remove: "You cannot remove that sign!" + not-enough-level: "Your island level is not high enough!" + no-permission: "You do not have permission to do that!" + not-on-island: "You must be on your island to do that!" + duplicate: "Duplicate sign placed" + no-warps-yet: "There are no warps available yet" + \ No newline at end of file diff --git a/WelcomeWarps/plugin.yml b/WelcomeWarps/plugin.yml new file mode 100755 index 0000000..e7718ca --- /dev/null +++ b/WelcomeWarps/plugin.yml @@ -0,0 +1,7 @@ +name: BSkyBlock-WelcomeWarps +main: bskyblock.addin.warps.Warp +version: 0.1 + +authors: [tastybento] + +depend: [BSkyBlock] diff --git a/WelcomeWarps/pom.xml b/WelcomeWarps/pom.xml new file mode 100644 index 0000000..240465c --- /dev/null +++ b/WelcomeWarps/pom.xml @@ -0,0 +1,63 @@ + + 4.0.0 + bskyblock.addon + WelcomeWarpSigns + 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.bukkit + bukkit + 1.12.2-R0.1-SNAPSHOT + provided + + + us.tastybento + bskyblock + LATEST + + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + \ No newline at end of file diff --git a/WelcomeWarps/src/bskyblock/addin/warps/AddonHelper.java b/WelcomeWarps/src/bskyblock/addin/warps/AddonHelper.java new file mode 100644 index 0000000..bb24ac6 --- /dev/null +++ b/WelcomeWarps/src/bskyblock/addin/warps/AddonHelper.java @@ -0,0 +1,36 @@ +package bskyblock.addin.warps; + +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 Warp plugin; + protected final BSkyBlock bSkyBlock; + + public AddonHelper(Warp 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/WelcomeWarps/src/bskyblock/addin/warps/CPItem.java b/WelcomeWarps/src/bskyblock/addin/warps/CPItem.java new file mode 100644 index 0000000..284f5a9 --- /dev/null +++ b/WelcomeWarps/src/bskyblock/addin/warps/CPItem.java @@ -0,0 +1,117 @@ +/******************************************************************************* + * This file is part of ASkyBlock. + * + * ASkyBlock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ASkyBlock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ASkyBlock. If not, see . + *******************************************************************************/ +package bskyblock.addin.warps; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; + +/** + * @author tastybento + * This class is for a control panel button that has an icon, a command + * to run if pressed or a link to + * another control panel. + */ +public class CPItem { + + private ItemStack item; + private String command; + private String nextSection; + + + /** + * A Control Panel item + * @param material + * @param name + * @param command + * @param nextSection + */ + public CPItem(Material material, String name, String command, String nextSection) { + this.command = command; + this.nextSection = nextSection; + item = new ItemStack(material); + ItemMeta meta = item.getItemMeta(); + // Handle multi line names (split by |) + List desc = new ArrayList(Arrays.asList(name.split("\\|"))); + meta.setDisplayName(ChatColor.WHITE + desc.get(0)); + if (desc.size() > 1) { + desc.remove(0); // Remove the name + meta.setLore(desc); + } + item.setItemMeta(meta); + } + + public CPItem(ItemStack itemStack, String name, String command, String nextSection) { + this.command = command; + this.nextSection = nextSection; + this.item = itemStack; + ItemMeta meta = item.getItemMeta(); + // Handle multi line names (split by |) + List desc = new ArrayList(Arrays.asList(name.split("\\|"))); + meta.setDisplayName(ChatColor.WHITE + desc.get(0)); + if (desc.size() > 1) { + desc.remove(0); // Remove the name + meta.setLore(desc); + } + item.setItemMeta(meta); + } + + // For warps + public CPItem(ItemStack itemStack, String command) { + this.command = command; + this.nextSection = ""; + this.item = itemStack; + } + + public void setLore(List lore) { + ItemMeta meta = item.getItemMeta(); + meta.setLore(lore); + item.setItemMeta(meta); + } + + /** + * @return the command + */ + public String getCommand() { + return command; + } + + /** + * @return the nextSection + */ + public String getNextSection() { + return nextSection; + } + + /** + * @param nextSection + * the nextSection to set + */ + public void setNextSection(String nextSection) { + this.nextSection = nextSection; + } + + public ItemStack getItem() { + return item; + } + +} diff --git a/WelcomeWarps/src/bskyblock/addin/warps/Warp.java b/WelcomeWarps/src/bskyblock/addin/warps/Warp.java new file mode 100644 index 0000000..89b90a8 --- /dev/null +++ b/WelcomeWarps/src/bskyblock/addin/warps/Warp.java @@ -0,0 +1,96 @@ +package bskyblock.addin.warps; + +import java.util.UUID; + +import org.bukkit.command.CommandSender; +import org.bukkit.plugin.java.JavaPlugin; + +import bskyblock.addin.warps.commands.Commands; +import bskyblock.addin.warps.config.LocaleManager; +import bskyblock.addin.warps.config.PluginConfig; +import us.tastybento.bskyblock.BSkyBlock; +import us.tastybento.bskyblock.config.BSBLocale; + +/** + * Addin to BSkyBlock that enables welcome warp signs + * @author tastybento + * + */ +public class Warp extends JavaPlugin { + + // The BSkyBlock plugin instance. + private BSkyBlock bSkyBlock; + + // Locale manager for this plugin + private LocaleManager localeManager; + + // Warp panel object + private WarpPanel warpPanel; + + // Warps signs object + private WarpSigns warpSigns; + + @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.isEnabled()) { + this.setEnabled(false); + return; + } + // Local locales + localeManager = new LocaleManager(this); + // Start warp signs + warpSigns = new WarpSigns(this, bSkyBlock); + getServer().getPluginManager().registerEvents(warpSigns, this); + // Start the warp panel and register it for clicks + warpPanel = new WarpPanel(this); + getServer().getPluginManager().registerEvents(warpPanel, this); + // Register commands + new Commands(this); + // Done + } + + @Override + public void onDisable(){ + // Save the warps + warpSigns.saveWarpList(); + } + + /** + * 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); + } + + /** + * @return default locale object + */ + public BSBLocale getLocale() { + return localeManager.getLocale(); + } + + public WarpPanel getWarpPanel() { + return warpPanel; + } + + public WarpSigns getWarpSigns() { + return warpSigns; + } + +} diff --git a/WelcomeWarps/src/bskyblock/addin/warps/WarpPanel.java b/WelcomeWarps/src/bskyblock/addin/warps/WarpPanel.java new file mode 100644 index 0000000..2eccc39 --- /dev/null +++ b/WelcomeWarps/src/bskyblock/addin/warps/WarpPanel.java @@ -0,0 +1,299 @@ +package bskyblock.addin.warps; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Sign; +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.InventoryType.SlotType; +import org.bukkit.inventory.Inventory; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.bukkit.inventory.meta.SkullMeta; + +import us.tastybento.bskyblock.config.Settings; +import us.tastybento.bskyblock.database.objects.Island; +import us.tastybento.bskyblock.database.objects.Island.SettingsFlag; +import us.tastybento.bskyblock.generators.IslandWorld; +import us.tastybento.bskyblock.util.Util; + +public class WarpPanel extends AddonHelper implements Listener { + private static final int PANELSIZE = 45; // Must be a multiple of 9 + private final static boolean DEBUG = false; + private List warpPanel; + private HashMap cachedWarps; + + /** + * @param plugin + */ + public WarpPanel(Warp plugin) { + super(plugin); + warpPanel = new ArrayList(); + cachedWarps = new HashMap(); + //plugin.getLogger().info("DEBUG: loading the warp panel of size " + plugin.getWarpSigns().listSortedWarps().size()); + // Load the cache + for (UUID playerUUID : plugin.getWarpSigns().listSortedWarps()) { + addWarp(playerUUID); + } + // Make the panels + updatePanel(); + } + + /** + * Adds a new warp to the cache. Does NOT update the panels + * @param playerUUID + */ + public void addWarp(UUID playerUUID) { + if (DEBUG) + plugin.getLogger().info("DEBUG: Adding warp"); + // Check cached warps + if (cachedWarps.containsKey(playerUUID)) { + if (DEBUG) + plugin.getLogger().info("DEBUG: Found in cache"); + // Get the item + ItemStack playerSkull = cachedWarps.get(playerUUID); + playerSkull = updateText(playerSkull, playerUUID); + return; + } + //plugin.getLogger().info("DEBUG: New skull"); + // Get the item + ItemStack playerSkull = getSkull(playerUUID); + if (playerSkull == null) { + // Nothing found and not available on the server + return; + } + // Update the sign text + playerSkull = updateText(playerSkull, playerUUID); + cachedWarps.put(playerUUID, playerSkull); + } + + /** + * Gets the skull for this player UUID + * @param playerUUID + * @return Player skull item + */ + @SuppressWarnings("deprecation") + private ItemStack getSkull(UUID playerUUID) { + String playerName = bSkyBlock.getPlayers().getName(playerUUID); + if (DEBUG) + plugin.getLogger().info("DEBUG: name of warp = " + playerName); + ItemStack playerSkull = new ItemStack(Material.SKULL_ITEM, 1, (short) 3); + if (playerName == null) { + if (DEBUG) + plugin.getLogger().warning("Warp for Player: UUID " + playerUUID.toString() + " is unknown on this server, skipping..."); + return null; + //playerName = playerUUID.toString().substring(0, 10); + } + SkullMeta meta = (SkullMeta) playerSkull.getItemMeta(); + meta.setOwner(playerName); + meta.setDisplayName(ChatColor.WHITE + playerName); + playerSkull.setItemMeta(meta); + return playerSkull; + } + public Inventory getWarpPanel(int panelNumber) { + //makePanel(); + if (panelNumber < 0) { + panelNumber = 0; + } else if (panelNumber > warpPanel.size()-1) { + panelNumber = warpPanel.size()-1; + } + return warpPanel.get(panelNumber); + } + + @SuppressWarnings("deprecation") + @EventHandler(priority = EventPriority.LOWEST, ignoreCancelled=true) + public void onInventoryClick(InventoryClickEvent event) { + Inventory inventory = event.getInventory(); // The inventory that was clicked in + if (inventory.getName() == null) { + return; + } + // The player that clicked the item + final Player player = (Player) event.getWhoClicked(); + String title = inventory.getTitle(); + if (!inventory.getTitle().startsWith(plugin.getLocale(player.getUniqueId()).get("warps.title") + " #")) { + return; + } + event.setCancelled(true); + if (event.getSlotType().equals(SlotType.OUTSIDE)) { + player.closeInventory(); + return; + } + if (event.getClick().equals(ClickType.SHIFT_RIGHT)) { + player.closeInventory(); + player.updateInventory(); + return; + } + ItemStack clicked = event.getCurrentItem(); // The item that was clicked + if (DEBUG) + plugin.getLogger().info("DEBUG: inventory size = " + inventory.getSize()); + if (DEBUG) + plugin.getLogger().info("DEBUG: clicked = " + clicked); + if (DEBUG) + plugin.getLogger().info("DEBUG: rawslot = " + event.getRawSlot()); + if (event.getRawSlot() >= event.getInventory().getSize() || clicked.getType() == Material.AIR) { + return; + } + int panelNumber = 0; + try { + panelNumber = Integer.valueOf(title.substring(title.indexOf('#')+ 1)); + } catch (Exception e) { + panelNumber = 0; + } + if (clicked.getItemMeta().hasDisplayName()) { + String command = ChatColor.stripColor(clicked.getItemMeta().getDisplayName()); + if (DEBUG) + plugin.getLogger().info("DEBUG: command = " + command); + if (command != null) { + if (command.equalsIgnoreCase(ChatColor.stripColor(plugin.getLocale().get("warps.next")))) { + player.closeInventory(); + Util.runCommand(player, Settings.ISLANDCOMMAND + " warps " + (panelNumber+1)); + } else if (command.equalsIgnoreCase(ChatColor.stripColor(plugin.getLocale().get("warps.previous")))) { + player.closeInventory(); + Util.runCommand(player, Settings.ISLANDCOMMAND + " warps " + (panelNumber-1)); + } else { + player.closeInventory(); + Util.sendMessage(player, ChatColor.GREEN + plugin.getLocale(player.getUniqueId()).get("warps.warpToPlayersSign").replace("[player]", command)); + Util.runCommand(player, Settings.ISLANDCOMMAND + " warp " + command); + } + } + } + } + + /** + * Update the text on all the warp icons. + */ + public void updateAllWarpText() { + if (DEBUG) + plugin.getLogger().info("DEBUG: update all Warps"); + for (UUID playerUUID : cachedWarps.keySet()) { + // Get the item + ItemStack playerSkull = cachedWarps.get(playerUUID); + playerSkull = updateText(playerSkull, playerUUID); + } + updatePanel(); + } + + /** + * Creates the inventory panels from the warp list and adds nav buttons + */ + public void updatePanel() { + // Clear the inventory panels + warpPanel.clear(); + Collection activeWarps = plugin.getWarpSigns().listSortedWarps(); + // Create the warp panels + if (DEBUG) + plugin.getLogger().info("DEBUG: warps size = " + activeWarps.size()); + int size = activeWarps.size(); + int panelNumber = size / (PANELSIZE-2); + int remainder = (size % (PANELSIZE-2)) + 8 + 2; + remainder -= (remainder % 9); + if (DEBUG) + plugin.getLogger().info("DEBUG: panel number = " + panelNumber + " remainder = " + remainder); + int i = 0; + // TODO: Make panel title a string + for (i = 0; i < panelNumber; i++) { + if (DEBUG) + plugin.getLogger().info("DEBUG: created panel " + (i+1)); + warpPanel.add(Bukkit.createInventory(null, PANELSIZE, plugin.getLocale().get("warps.title") + " #" + (i+1))); + } + // Make the last panel + if (DEBUG) + plugin.getLogger().info("DEBUG: created panel " + (i+1)); + warpPanel.add(Bukkit.createInventory(null, remainder, plugin.getLocale().get("warps.title") + " #" + (i+1))); + panelNumber = 0; + int slot = 0; + // Run through all the warps and add them to the inventories with nav buttons + for (UUID playerUUID: activeWarps) { + ItemStack icon = cachedWarps.get(playerUUID); + if (icon != null) { + warpPanel.get(panelNumber).setItem(slot++, icon); + + // Check if the panel is full + if (slot == PANELSIZE-2) { + // Add navigation buttons + if (panelNumber > 0) { + warpPanel.get(panelNumber).setItem(slot++, new CPItem(Material.SIGN,plugin.getLocale().get("warps.previous"),"warps " + (panelNumber-1),"").getItem()); + } + warpPanel.get(panelNumber).setItem(slot, new CPItem(Material.SIGN,plugin.getLocale().get("warps.next"),"warps " + (panelNumber+1),"").getItem()); + // Move onto the next panel + panelNumber++; + slot = 0; + } + } + } + if (remainder != 0 && panelNumber > 0) { + warpPanel.get(panelNumber).setItem(slot++, new CPItem(Material.SIGN,plugin.getLocale().get("warps.previous"),"warps " + (panelNumber-1),"").getItem()); + } + } + + /** + * Updates the meta text on the skull by looking at the warp sign + * This MUST be run 1 TICK AFTER the sign has been created otherwise the sign is blank + * @param playerSkull + * @param playerUUID + * @return updated skull item stack + */ + private ItemStack updateText(ItemStack playerSkull, final UUID playerUUID) { + if (DEBUG) + plugin.getLogger().info("DEBUG: Updating text on item"); + ItemMeta meta = playerSkull.getItemMeta(); + //get the sign info + Location signLocation = plugin.getWarpSigns().getWarp(playerUUID); + if (signLocation == null) { + plugin.getWarpSigns().removeWarp(playerUUID); + return playerSkull; + } + //plugin.getLogger().info("DEBUG: block type = " + signLocation.getBlock().getType()); + // Get the sign info if it exists + if (signLocation.getBlock().getType().equals(Material.SIGN_POST) || signLocation.getBlock().getType().equals(Material.WALL_SIGN)) { + Sign sign = (Sign)signLocation.getBlock().getState(); + List lines = new ArrayList(Arrays.asList(sign.getLines())); + // Check for PVP and add warning + Island island = bSkyBlock.getIslands().getIsland(playerUUID); + if (island != null) { + if ((signLocation.getWorld().equals(IslandWorld.getIslandWorld()) && island.getFlag(SettingsFlag.PVP_OVERWORLD)) + || (signLocation.getWorld().equals(IslandWorld.getNetherWorld()) && island.getFlag(SettingsFlag.PVP_NETHER))) { + if (DEBUG) + plugin.getLogger().info("DEBUG: pvp warning added"); + lines.add(ChatColor.RED + bSkyBlock.getLocale(playerUUID).get("igs." + SettingsFlag.PVP_OVERWORLD)); + } + } + meta.setLore(lines); + if (DEBUG) + plugin.getLogger().info("DEBUG: lines = " + lines); + } + playerSkull.setItemMeta(meta); + return playerSkull; + } + + /** + * Only change the text of the warp + * @param playerUUID + */ + public void updateWarp(UUID playerUUID) { + if (DEBUG) + plugin.getLogger().info("DEBUG: update Warp"); + + if (cachedWarps.containsKey(playerUUID)) { + // Get the item + ItemStack playerSkull = cachedWarps.get(playerUUID); + playerSkull = updateText(playerSkull, playerUUID); + updatePanel(); + } else { + plugin.getLogger().warning("Warps: update requested, but player unknown " + playerUUID.toString()); + } + } +} diff --git a/WelcomeWarps/src/bskyblock/addin/warps/WarpSigns.java b/WelcomeWarps/src/bskyblock/addin/warps/WarpSigns.java new file mode 100644 index 0000000..d3acf71 --- /dev/null +++ b/WelcomeWarps/src/bskyblock/addin/warps/WarpSigns.java @@ -0,0 +1,440 @@ +package bskyblock.addin.warps; + +import java.beans.IntrospectionException; +import java.lang.reflect.InvocationTargetException; +import java.sql.SQLException; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.TreeMap; +import java.util.UUID; + +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.Listener; +import org.bukkit.event.block.BlockBreakEvent; +import org.bukkit.event.block.SignChangeEvent; + +import bskyblock.addin.warps.config.Settings; +import bskyblock.addin.warps.database.object.Warps; +import bskyblock.addin.warps.event.WarpCreateEvent; +import bskyblock.addin.warps.event.WarpListEvent; +import bskyblock.addin.warps.event.WarpRemoveEvent; +import us.tastybento.bskyblock.BSkyBlock; +import us.tastybento.bskyblock.database.BSBDatabase; +import us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler; +import us.tastybento.bskyblock.generators.IslandWorld; +import us.tastybento.bskyblock.util.Util; +import us.tastybento.bskyblock.util.VaultHelper; + +/** + * Handles warping. Players can add one sign + * + * @author tastybento + * + */ +public class WarpSigns extends AddonHelper implements Listener { + //private final static boolean DEBUG = false; + private BSkyBlock bSkyBlock; + // Map of all warps stored as player, warp sign Location + private Map warpList; + // Database handler for level data + private AbstractDatabaseHandler handler; + + // The BSkyBlock database object + private BSBDatabase database; + + + /** + * @param plugin + */ + @SuppressWarnings("unchecked") + public WarpSigns(Warp plugin, BSkyBlock bSkyBlock) { + super(plugin); + this.bSkyBlock = bSkyBlock; + // Get the BSkyBlock database + database = BSBDatabase.getDatabase(); + // Set up the database handler to store and retrieve Island classes + // Note that these are saved by the BSkyBlock database + handler = (AbstractDatabaseHandler) database.getHandler(bSkyBlock, Warps.class); + // Load the warps + loadWarpList(); + } + + /** + * Checks to see if a sign has been broken + * @param e + */ + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = false) + public void onSignBreak(BlockBreakEvent e) { + Block b = e.getBlock(); + Player player = e.getPlayer(); + if (b.getWorld().equals(IslandWorld.getIslandWorld()) || b.getWorld().equals(IslandWorld.getNetherWorld())) { + if (b.getType().equals(Material.SIGN_POST) || b.getType().equals(Material.WALL_SIGN)) { + Sign s = (Sign) b.getState(); + if (s != null) { + //plugin.getLogger().info("DEBUG: sign found at location " + s.toString()); + if (s.getLine(0).equalsIgnoreCase(ChatColor.GREEN + plugin.getLocale().get("warps.welcomeLine"))) { + // Do a quick check to see if this sign location is in + //plugin.getLogger().info("DEBUG: welcome sign"); + // the list of warp signs + if (warpList.containsValue(s.getLocation())) { + //plugin.getLogger().info("DEBUG: warp sign is in list"); + // Welcome sign detected - check to see if it is + // this player's sign + if ((warpList.containsKey(player.getUniqueId()) && warpList.get(player.getUniqueId()).equals(s.getLocation()))) { + // Player removed sign + removeWarp(s.getLocation()); + Bukkit.getPluginManager().callEvent(new WarpRemoveEvent(plugin, s.getLocation(), player.getUniqueId())); + } else if (player.isOp() || player.hasPermission(Settings.PERMPREFIX + "mod.removesign")) { + // Op or mod removed sign + Util.sendMessage(player, ChatColor.GREEN + plugin.getLocale(player.getUniqueId()).get("warps.removed")); + removeWarp(s.getLocation()); + Bukkit.getPluginManager().callEvent(new WarpRemoveEvent(plugin, s.getLocation(), player.getUniqueId())); + } else { + // Someone else's sign - not allowed + Util.sendMessage(player, ChatColor.RED + plugin.getLocale(player.getUniqueId()).get("warps.error.no-remove")); + e.setCancelled(true); + } + } + } + } + } + } + } + + /** + * Event handler for Sign Changes + * + * @param e + */ + @EventHandler(priority = EventPriority.NORMAL, ignoreCancelled = false) + public void onSignWarpCreate(SignChangeEvent e) { + //plugin.getLogger().info("DEBUG: SignChangeEvent called"); + String title = e.getLine(0); + Player player = e.getPlayer(); + if (player.getWorld().equals(IslandWorld.getIslandWorld()) || player.getWorld().equals(IslandWorld.getNetherWorld())) { + //plugin.getLogger().info("DEBUG: Correct world"); + if (e.getBlock().getType().equals(Material.SIGN_POST) || e.getBlock().getType().equals(Material.WALL_SIGN)) { + + //plugin.getLogger().info("DEBUG: The first line of the sign says " + title); + // Check if someone is changing their own sign + // This should never happen !! + if (title.equalsIgnoreCase(plugin.getLocale().get("warps.welcomeLine"))) { + //plugin.getLogger().info("DEBUG: Welcome sign detected"); + // Welcome sign detected - check permissions + if (!(VaultHelper.hasPerm(player, Settings.PERMPREFIX + "island.addwarp"))) { + Util.sendMessage(player, ChatColor.RED + plugin.getLocale(player.getUniqueId()).get("warps.error.no-permission")); + return; + } + /* + if(!(ASkyBlockAPI.getInstance().getLongIslandLevel(player.getUniqueId()) > Settings.warpLevelsRestriction)){ + Util.sendMessage(player, ChatColor.RED + plugin.getLocale(player.getUniqueId()).get("warps.error.NotEnoughLevel")); + return; + } + */ + // Check that the player is on their island + if (!(bSkyBlock.getIslands().playerIsOnIsland(player))) { + Util.sendMessage(player, ChatColor.RED + plugin.getLocale(player.getUniqueId()).get("warps.error.not-on-island")); + e.setLine(0, ChatColor.RED + plugin.getLocale().get("warps.welcomeLine")); + return; + } + // Check if the player already has a sign + final Location oldSignLoc = getWarp(player.getUniqueId()); + if (oldSignLoc == null) { + //plugin.getLogger().info("DEBUG: Player does not have a sign already"); + // First time the sign has been placed or this is a new + // sign + if (addWarp(player.getUniqueId(), e.getBlock().getLocation())) { + Util.sendMessage(player, ChatColor.GREEN + plugin.getLocale(player.getUniqueId()).get("warps.success")); + e.setLine(0, ChatColor.GREEN + plugin.getLocale().get("warps.welcomeLine")); + for (int i = 1; i<4; i++) { + e.setLine(i, ChatColor.translateAlternateColorCodes('&', e.getLine(i))); + } + } else { + Util.sendMessage(player, ChatColor.RED + plugin.getLocale(player.getUniqueId()).get("warps.error.duplicate")); + e.setLine(0, ChatColor.RED + plugin.getLocale().get("warps.welcomeLine")); + for (int i = 1; i<4; i++) { + e.setLine(i, ChatColor.translateAlternateColorCodes('&', e.getLine(i))); + } + } + } else { + //plugin.getLogger().info("DEBUG: Player already has a Sign"); + // A sign already exists. Check if it still there and if + // so, + // deactivate it + Block oldSignBlock = oldSignLoc.getBlock(); + if (oldSignBlock.getType().equals(Material.SIGN_POST) || oldSignBlock.getType().equals(Material.WALL_SIGN)) { + // The block is still a sign + //plugin.getLogger().info("DEBUG: The block is still a sign"); + Sign oldSign = (Sign) oldSignBlock.getState(); + if (oldSign != null) { + //plugin.getLogger().info("DEBUG: Sign block is a sign"); + if (oldSign.getLine(0).equalsIgnoreCase(ChatColor.GREEN + plugin.getLocale().get("warps.welcomeLine"))) { + //plugin.getLogger().info("DEBUG: Old sign had a green welcome"); + oldSign.setLine(0, ChatColor.RED + plugin.getLocale().get("warps.welcomeLine")); + oldSign.update(true, false); + Util.sendMessage(player, ChatColor.RED + plugin.getLocale(player.getUniqueId()).get("warps.deactivate")); + removeWarp(player.getUniqueId()); + Bukkit.getPluginManager().callEvent(new WarpRemoveEvent(plugin, oldSign.getLocation(), player.getUniqueId())); + } + } + } + // Set up the warp + if (addWarp(player.getUniqueId(), e.getBlock().getLocation())) { + Util.sendMessage(player, ChatColor.GREEN + plugin.getLocale(player.getUniqueId()).get("warps.error.success")); + e.setLine(0, ChatColor.GREEN + plugin.getLocale().get("warps.welcomeLine")); + } else { + Util.sendMessage(player, ChatColor.RED + plugin.getLocale(player.getUniqueId()).get("warps.error.duplicate")); + e.setLine(0, ChatColor.RED + plugin.getLocale().get("warps.welcomeLine")); + } + } + } + } + } + } + + /** + * Saves the warp lists to the database + */ + public void saveWarpList() { + if (warpList == null) { + return; + } + //plugin.getLogger().info("Saving warps..."); + try { + handler.saveObject(new Warps().save(warpList)); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException + | InstantiationException | NoSuchMethodException | IntrospectionException | SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + /** + * Loads the warps and checks if they still exist + */ + public void loadWarpList() { + plugin.getLogger().info("Loading warps..."); + try { + Warps warps = handler.loadObject("warps"); + // If there's nothing there, start fresh + if (warps == null) { + warpList = new HashMap<>(); + } else { + warpList = warps.getWarpSigns(); + } + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException + | SecurityException | ClassNotFoundException | IntrospectionException | SQLException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + Iterator> it = warpList.entrySet().iterator(); + while (it.hasNext()) { + Entry en = it.next(); + // Chck the warp sign + Block b = en.getValue().getBlock(); + // Check that a warp sign is still there + if (!b.getType().equals(Material.SIGN_POST) && !b.getType().equals(Material.WALL_SIGN)) { + plugin.getLogger().warning("Warp at location " + en.getValue() + " has no sign - removing."); + it.remove(); + } + } + } + + /** + * Stores warps in the warp array + * + * @param playerUUID + * @param loc + */ + public boolean addWarp(final UUID playerUUID, final Location loc) { + if (playerUUID == null) { + return false; + } + // Do not allow warps to be in the same location + if (warpList.containsValue(loc)) { + return false; + } + // Remove the old warp if it existed + if (warpList.containsKey(playerUUID)) { + warpList.remove(playerUUID); + } + warpList.put(playerUUID, loc); + saveWarpList(); + // Update warp signs + // Run one tick later because text gets updated at the end of tick + plugin.getServer().getScheduler().runTask(plugin, new Runnable() { + + @Override + public void run() { + plugin.getWarpPanel().addWarp(playerUUID); + plugin.getWarpPanel().updatePanel(); + Bukkit.getPluginManager().callEvent(new WarpCreateEvent(plugin, loc, playerUUID)); + }}); + return true; + } + + /** + * Removes a warp when the welcome sign is destroyed. Called by + * WarpSigns.java. + * + * @param uuid + */ + public void removeWarp(UUID uuid) { + if (warpList.containsKey(uuid)) { + popSign(warpList.get(uuid)); + warpList.remove(uuid); + } + saveWarpList(); + // Update warp signs + // Run one tick later because text gets updated at the end of tick + plugin.getServer().getScheduler().runTask(plugin, new Runnable() { + + @Override + public void run() { + plugin.getWarpPanel().updatePanel(); + + }}); + } + + /** + * Changes the sign to red if it exists + * @param loc + */ + private void popSign(Location loc) { + Block b = loc.getBlock(); + if (b.getType().equals(Material.SIGN_POST) || b.getType().equals(Material.WALL_SIGN)) { + Sign s = (Sign) b.getState(); + if (s != null) { + if (s.getLine(0).equalsIgnoreCase(ChatColor.GREEN + plugin.getLocale().get("warps.welcomeLine"))) { + s.setLine(0, ChatColor.RED + plugin.getLocale().get("warps.welcomeLine")); + s.update(true, false); + } + } + } + } + + /** + * Removes a warp at a location. + * + * @param loc + */ + public void removeWarp(Location loc) { + //plugin.getLogger().info("Asked to remove warp at " + loc); + popSign(loc); + Iterator> it = warpList.entrySet().iterator(); + while (it.hasNext()) { + Entry en = it.next(); + if (en.getValue().equals(loc)) { + // Inform player + Player p = plugin.getServer().getPlayer(en.getKey()); + if (p != null) { + // Inform the player + Util.sendMessage(p, ChatColor.RED + plugin.getLocale(p.getUniqueId()).get("warps.sign-removed")); + } + /* + else { + plugin.getMessages().setMessage(en.getKey(), ChatColor.RED + plugin.myLocale(en.getKey()).warpssignRemoved); + } + */ + it.remove(); + } + } + saveWarpList(); + plugin.getWarpPanel().updatePanel(); + } + + /** + * Lists all the known warps + * + * @return String set of warps + */ + public Set listWarps() { + // Check if any of the warp locations are null + Iterator> it = warpList.entrySet().iterator(); + while (it.hasNext()) { + Entry en = it.next(); + // Check if the location of the warp still exists, if not, delete it + if (en.getValue() == null) { + it.remove(); + } + } + return warpList.keySet(); + } + + /** + * @return Sorted list of warps with most recent players listed first + */ + public Collection listSortedWarps() { + // Bigger value of time means a more recent login + TreeMap map = new TreeMap(); + Iterator> it = warpList.entrySet().iterator(); + while (it.hasNext()) { + Entry en = it.next(); + // Check if the location of the warp still exists, if not, delete it + if (en.getValue() == null) { + it.remove(); + } else { + UUID uuid = en.getKey(); + // If never played, will be zero + long lastPlayed = plugin.getServer().getOfflinePlayer(uuid).getLastPlayed(); + // This aims to avoid the chance that players logged off at exactly the same time + if (!map.isEmpty() && map.containsKey(lastPlayed)) { + lastPlayed = map.firstKey() - 1; + } + map.put(lastPlayed, uuid); + } + } + + Collection result = map.descendingMap().values(); + // Fire event + WarpListEvent event = new WarpListEvent(plugin, result); + plugin.getServer().getPluginManager().callEvent(event); + // Get the result of any changes by listeners + result = event.getWarps(); + return result; + } + /** + * Provides the location of the warp for player or null if one is not found + * + * @param playerUUID + * - the warp requested + * @return Location of warp + */ + public Location getWarp(UUID playerUUID) { + if (playerUUID != null && warpList.containsKey(playerUUID)) { + if (warpList.get(playerUUID) == null) { + warpList.remove(playerUUID); + return null; + } + return warpList.get(playerUUID); + } else { + return null; + } + } + + /** + * @param location + * @return Name of warp owner + */ + public String getWarpOwner(Location location) { + for (UUID playerUUID : warpList.keySet()) { + if (location.equals(warpList.get(playerUUID))) { + return bSkyBlock.getPlayers().getName(playerUUID); + } + } + return ""; + } + +} \ No newline at end of file diff --git a/WelcomeWarps/src/bskyblock/addin/warps/commands/Commands.java b/WelcomeWarps/src/bskyblock/addin/warps/commands/Commands.java new file mode 100644 index 0000000..84ff519 --- /dev/null +++ b/WelcomeWarps/src/bskyblock/addin/warps/commands/Commands.java @@ -0,0 +1,270 @@ +package bskyblock.addin.warps.commands; + +import java.util.Set; +import java.util.UUID; + +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; +import org.bukkit.block.Sign; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import bskyblock.addin.warps.AddonHelper; +import bskyblock.addin.warps.Warp; +import us.tastybento.bskyblock.api.commands.ArgumentHandler; +import us.tastybento.bskyblock.api.commands.CanUseResp; +import us.tastybento.bskyblock.config.Settings; +import us.tastybento.bskyblock.database.objects.Island; +import us.tastybento.bskyblock.database.objects.Island.SettingsFlag; +import us.tastybento.bskyblock.generators.IslandWorld; +import us.tastybento.bskyblock.util.Util; +import us.tastybento.bskyblock.util.VaultHelper; + +public class Commands extends AddonHelper { + + public Commands(Warp plugin) { + super(plugin); + setupCommands(); + } + + private void setupCommands() { + // island warp command + bSkyBlock.addSubCommand(new ArgumentHandler("island") { + + @Override + public CanUseResp canUse(CommandSender sender) { + if (!(sender instanceof Player)) { + return new CanUseResp(false); + } + if (VaultHelper.hasPerm((Player)sender, Settings.PERMPREFIX + "island.warp")) { + return new CanUseResp(true); + } + return new CanUseResp(false); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (args.length == 1) { + // Warp somewhere command + Player player = (Player)sender; + final Set warpList = plugin.getWarpSigns().listWarps(); + if (warpList.isEmpty()) { + Util.sendMessage(player, ChatColor.YELLOW + plugin.getLocale(player.getUniqueId()).get("warps.errorNoWarpsYet")); + if (VaultHelper.hasPerm(player, Settings.PERMPREFIX + "island.addwarp")) { + Util.sendMessage(player, ChatColor.YELLOW + plugin.getLocale().get("warps.warpTip")); + } else { + Util.sendMessage(player, ChatColor.RED + plugin.getLocale(player.getUniqueId()).get("error.NoPermission")); + } + return; + } else { + // Check if this is part of a name + UUID foundWarp = null; + for (UUID warp : warpList) { + if (warp == null) + continue; + if (bSkyBlock.getPlayers().getName(warp).toLowerCase().equals(args[0].toLowerCase())) { + foundWarp = warp; + break; + } else if (bSkyBlock.getPlayers().getName(warp).toLowerCase().startsWith(args[0].toLowerCase())) { + foundWarp = warp; + } + } + if (foundWarp == null) { + Util.sendMessage(player, ChatColor.RED + plugin.getLocale(player.getUniqueId()).get("warps.error.DoesNotExist")); + return; + } else { + // Warp exists! + final Location warpSpot = plugin.getWarpSigns().getWarp(foundWarp); + // Check if the warp spot is safe + if (warpSpot == null) { + Util.sendMessage(player, ChatColor.RED + plugin.getLocale(player.getUniqueId()).get("warps.error.NotReadyYet")); + plugin.getLogger().warning("Null warp found, owned by " + bSkyBlock.getPlayers().getName(foundWarp)); + return; + } + // Find out if island is locked + // TODO: Fire event + + Island island = bSkyBlock.getIslands().getIsland(foundWarp); + boolean pvp = false; + if ((warpSpot.getWorld().equals(IslandWorld.getIslandWorld()) && island.getFlag(SettingsFlag.PVP_OVERWORLD)) + || (warpSpot.getWorld().equals(IslandWorld.getNetherWorld()) && island.getFlag(SettingsFlag.PVP_NETHER))) { + pvp = true; + } + // Find out which direction the warp is facing + Block b = warpSpot.getBlock(); + if (b.getType().equals(Material.SIGN_POST) || b.getType().equals(Material.WALL_SIGN)) { + Sign sign = (Sign) b.getState(); + org.bukkit.material.Sign s = (org.bukkit.material.Sign) sign.getData(); + BlockFace directionFacing = s.getFacing(); + Location inFront = b.getRelative(directionFacing).getLocation(); + Location oneDown = b.getRelative(directionFacing).getRelative(BlockFace.DOWN).getLocation(); + if ((Util.isSafeLocation(inFront))) { + warpPlayer(player, inFront, foundWarp, directionFacing, pvp); + return; + } else if (b.getType().equals(Material.WALL_SIGN) && Util.isSafeLocation(oneDown)) { + // Try one block down if this is a wall sign + warpPlayer(player, oneDown, foundWarp, directionFacing, pvp); + return; + } + } else { + // Warp has been removed + Util.sendMessage(player, ChatColor.RED + plugin.getLocale(player.getUniqueId()).get("warps.error.DoesNotExist")); + plugin.getWarpSigns().removeWarp(warpSpot); + return; + } + if (!(Util.isSafeLocation(warpSpot))) { + Util.sendMessage(player, ChatColor.RED + plugin.getLocale(player.getUniqueId()).get("warps.error.NotSafe")); + // WALL_SIGN's will always be unsafe if the place in front is obscured. + if (b.getType().equals(Material.SIGN_POST)) { + plugin.getLogger().warning( + "Unsafe warp found at " + warpSpot.toString() + " owned by " + bSkyBlock.getPlayers().getName(foundWarp)); + + } + return; + } else { + final Location actualWarp = new Location(warpSpot.getWorld(), warpSpot.getBlockX() + 0.5D, warpSpot.getBlockY(), + warpSpot.getBlockZ() + 0.5D); + player.teleport(actualWarp); + if (pvp) { + Util.sendMessage(player, ChatColor.BOLD + "" + ChatColor.RED + bSkyBlock.getLocale(player.getUniqueId()).get("igs." + SettingsFlag.PVP_OVERWORLD + " " + bSkyBlock.getLocale(player.getUniqueId()).get("igs.Allowed"))); + player.getWorld().playSound(player.getLocation(), Sound.ENTITY_ARROW_HIT, 1F, 1F); + } else { + player.getWorld().playSound(player.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 1F, 1F); + } + return; + } + } + } + } + } + + @Override + public Set tabComplete(CommandSender sender, String[] args) { + return null; + } + + @Override + public String[] usage(CommandSender sender) { + return new String[]{"[player]", "Warp to player's warp sign"}; + } + }.alias("warp")); + + // island warps command + bSkyBlock.addSubCommand(new ArgumentHandler("island") { + + @Override + public CanUseResp canUse(CommandSender sender) { + if (sender instanceof Player) { + VaultHelper.hasPerm((Player)sender, Settings.PERMPREFIX + "island.warp"); + return new CanUseResp(true); + } + return new CanUseResp(false); + } + + @Override + public void execute(CommandSender sender, String[] args) { + if (sender instanceof Player) { + Player player = (Player)sender; + if (plugin.getWarpSigns().listWarps().isEmpty()) { + Util.sendMessage(player, ChatColor.YELLOW + plugin.getLocale(player.getUniqueId()).get("warps.error.no-warps-yet")); + if (VaultHelper.hasPerm(player, Settings.PERMPREFIX + "island.addwarp") && bSkyBlock.getIslands().playerIsOnIsland(player)) { + Util.sendMessage(player, ChatColor.YELLOW + plugin.getLocale().get("warps.warpTip")); + } + } else { + player.openInventory(plugin.getWarpPanel().getWarpPanel(0)); + } + } + } + + @Override + public Set tabComplete(CommandSender sender, String[] args) { + return null; + } + + @Override + public String[] usage(CommandSender sender) { + return new String[]{"", "View warps"}; + } + }.alias("warps")); + + + } + + /** + * Warps a player to a spot in front of a sign + * @param player + * @param inFront + * @param foundWarp + * @param directionFacing + */ + private void warpPlayer(Player player, Location inFront, UUID foundWarp, BlockFace directionFacing, boolean pvp) { + // convert blockface to angle + float yaw = blockFaceToFloat(directionFacing); + final Location actualWarp = new Location(inFront.getWorld(), inFront.getBlockX() + 0.5D, inFront.getBlockY(), + inFront.getBlockZ() + 0.5D, yaw, 30F); + player.teleport(actualWarp); + if (pvp) { + Util.sendMessage(player, ChatColor.BOLD + "" + ChatColor.RED + bSkyBlock.getLocale(player.getUniqueId()).get("igs." + SettingsFlag.PVP_OVERWORLD + " " + bSkyBlock.getLocale(player.getUniqueId()).get("igs.allowed"))); + player.getWorld().playSound(player.getLocation(), Sound.ENTITY_ARROW_HIT, 1F, 1F); + + } else { + + player.getWorld().playSound(player.getLocation(), Sound.ENTITY_BAT_TAKEOFF, 1F, 1F); + + } + Player warpOwner = plugin.getServer().getPlayer(foundWarp); + if (warpOwner != null && !warpOwner.equals(player)) { + Util.sendMessage(warpOwner, plugin.getLocale(foundWarp).get("warps.PlayerWarped").replace("[name]", player.getName())); + } + } + + /** + * Converts block face direction to radial degrees. Returns 0 if block face + * is not radial. + * + * @param face + * @return degrees + */ + public float blockFaceToFloat(BlockFace face) { + switch (face) { + case EAST: + return 90F; + case EAST_NORTH_EAST: + return 67.5F; + case EAST_SOUTH_EAST: + return 0F; + case NORTH: + return 0F; + case NORTH_EAST: + return 45F; + case NORTH_NORTH_EAST: + return 22.5F; + case NORTH_NORTH_WEST: + return 337.5F; + case NORTH_WEST: + return 315F; + case SOUTH: + return 180F; + case SOUTH_EAST: + return 135F; + case SOUTH_SOUTH_EAST: + return 157.5F; + case SOUTH_SOUTH_WEST: + return 202.5F; + case SOUTH_WEST: + return 225F; + case WEST: + return 270F; + case WEST_NORTH_WEST: + return 292.5F; + case WEST_SOUTH_WEST: + return 247.5F; + default: + return 0F; + } + } +} diff --git a/WelcomeWarps/src/bskyblock/addin/warps/config/LocaleManager.java b/WelcomeWarps/src/bskyblock/addin/warps/config/LocaleManager.java new file mode 100644 index 0000000..3146338 --- /dev/null +++ b/WelcomeWarps/src/bskyblock/addin/warps/config/LocaleManager.java @@ -0,0 +1,28 @@ +package bskyblock.addin.warps.config; + +import java.util.UUID; + +import bskyblock.addin.warps.Warp; +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(Warp 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/WelcomeWarps/src/bskyblock/addin/warps/config/PluginConfig.java b/WelcomeWarps/src/bskyblock/addin/warps/config/PluginConfig.java new file mode 100644 index 0000000..a29d1db --- /dev/null +++ b/WelcomeWarps/src/bskyblock/addin/warps/config/PluginConfig.java @@ -0,0 +1,95 @@ +package bskyblock.addin.warps.config; + +import java.util.HashMap; + +import org.apache.commons.lang.StringUtils; +import org.bukkit.Material; +import org.bukkit.material.MaterialData; + +import bskyblock.addin.warps.Warp; + +public class PluginConfig { + private static final boolean DEBUG = false; + + /** + * Loads the various settings from the config.yml file into the plugin + */ + public PluginConfig(Warp 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/WelcomeWarps/src/bskyblock/addin/warps/config/Settings.java b/WelcomeWarps/src/bskyblock/addin/warps/config/Settings.java new file mode 100644 index 0000000..44485ae --- /dev/null +++ b/WelcomeWarps/src/bskyblock/addin/warps/config/Settings.java @@ -0,0 +1,23 @@ +package bskyblock.addin.warps.config; + +import java.util.HashMap; + +import org.bukkit.material.MaterialData; + +public class Settings { + + public static String PERMPREFIX; + 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/WelcomeWarps/src/bskyblock/addin/warps/database/object/Warps.java b/WelcomeWarps/src/bskyblock/addin/warps/database/object/Warps.java new file mode 100644 index 0000000..483575a --- /dev/null +++ b/WelcomeWarps/src/bskyblock/addin/warps/database/object/Warps.java @@ -0,0 +1,38 @@ +package bskyblock.addin.warps.database.object; + +import java.util.Map; +import java.util.UUID; + +import org.bukkit.Location; + +import us.tastybento.bskyblock.database.objects.DataObject; + +public class Warps extends DataObject { + + private String uniqueId = "warps"; + private Map warpSigns; + + @Override + public String getUniqueId() { + return uniqueId; + } + + @Override + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + + public Map getWarpSigns() { + return warpSigns; + } + + public void setWarpSigns(Map warpSigns) { + this.warpSigns = warpSigns; + } + + public Warps save(Map warpList) { + this.warpSigns = warpList; + return this; + } + +} diff --git a/WelcomeWarps/src/bskyblock/addin/warps/event/WarpCreateEvent.java b/WelcomeWarps/src/bskyblock/addin/warps/event/WarpCreateEvent.java new file mode 100644 index 0000000..39bec29 --- /dev/null +++ b/WelcomeWarps/src/bskyblock/addin/warps/event/WarpCreateEvent.java @@ -0,0 +1,54 @@ +package bskyblock.addin.warps.event; + +import java.util.UUID; + +import org.bukkit.Location; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +import bskyblock.addin.warps.Warp; + +/** + * This event is fired when a Warp is created + * A Listener to this event can use it only to get informations. e.g: broadcast something + * + * @author Poslovitch + * + */ +public class WarpCreateEvent extends Event{ + private static final HandlerList handlers = new HandlerList(); + + private Location warpLoc; + private UUID creator; + + /** + * @param plugin + * @param warpLoc + * @param creator + */ + public WarpCreateEvent(Warp plugin, Location warpLoc, UUID creator){ + this.warpLoc = warpLoc; + this.creator = creator; + } + + /** + * Get the location of the created Warp + * @return created warp's location + */ + public Location getWarpLocation(){return this.warpLoc;} + + /** + * Get who has created the warp + * @return the warp's creator + */ + public UUID getCreator(){return this.creator;} + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/WelcomeWarps/src/bskyblock/addin/warps/event/WarpListEvent.java b/WelcomeWarps/src/bskyblock/addin/warps/event/WarpListEvent.java new file mode 100644 index 0000000..4dc6b2a --- /dev/null +++ b/WelcomeWarps/src/bskyblock/addin/warps/event/WarpListEvent.java @@ -0,0 +1,75 @@ +/******************************************************************************* + * This file is part of ASkyBlock. + * + * ASkyBlock is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * ASkyBlock is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with ASkyBlock. If not, see . + *******************************************************************************/ + +package bskyblock.addin.warps.event; + +import java.util.Collection; +import java.util.UUID; + +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +import bskyblock.addin.warps.Warp; + +/** + * This event is fired when request is made for a sorted list of warps or when + * the API updateWarpPanel method is called. + * A listener to this event can reorder or rewrite the warp list by using setWarps. + * This new order will then be used in the warp panel. + * + * @author tastybento + * + */ +public class WarpListEvent extends Event { + private static final HandlerList handlers = new HandlerList(); + private Collection warps; + + /** + * @param plugin + * @param warps + */ + public WarpListEvent(Warp plugin, Collection warps) { + this.warps = warps; + } + + + /** + *The warp list is a collection of player UUID's and the default order is + * that players with the most recent login will be first. + * @return the warps + */ + public Collection getWarps() { + return warps; + } + + /** + * @param warps the warps to set + */ + public void setWarps(Collection warps) { + this.warps = warps; + } + + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} diff --git a/WelcomeWarps/src/bskyblock/addin/warps/event/WarpRemoveEvent.java b/WelcomeWarps/src/bskyblock/addin/warps/event/WarpRemoveEvent.java new file mode 100644 index 0000000..100235e --- /dev/null +++ b/WelcomeWarps/src/bskyblock/addin/warps/event/WarpRemoveEvent.java @@ -0,0 +1,54 @@ +package bskyblock.addin.warps.event; + +import java.util.UUID; + +import org.bukkit.Location; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +import bskyblock.addin.warps.Warp; + +/** + * This event is fired when a Warp is removed (when a warp sign is broken) + * A Listener to this event can use it only to get informations. e.g: broadcast something + * + * @author Poslovitch + * + */ +public class WarpRemoveEvent extends Event{ + private static final HandlerList handlers = new HandlerList(); + + private Location warpLoc; + private UUID remover; + + /** + * @param plugin + * @param warpLoc + * @param remover + */ + public WarpRemoveEvent(Warp plugin, Location warpLoc, UUID remover){ + this.warpLoc = warpLoc; + this.remover = remover; + } + + /** + * Get the location of the removed Warp + * @return removed warp's location + */ + public Location getWarpLocation(){return this.warpLoc;} + + /** + * Get who has removed the warp + * @return the warp's remover + */ + public UUID getRemover(){return this.remover;} + + @Override + public HandlerList getHandlers() { + return handlers; + } + + public static HandlerList getHandlerList() { + return handlers; + } +} \ No newline at end of file