/******************************************************************************* * 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 <http://www.gnu.org/licenses/>. *******************************************************************************/ package com.wasteofplastic.askyblock; 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.configuration.file.YamlConfiguration; 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 com.wasteofplastic.askyblock.events.WarpCreateEvent; import com.wasteofplastic.askyblock.events.WarpListEvent; import com.wasteofplastic.askyblock.events.WarpRemoveEvent; import com.wasteofplastic.askyblock.util.Util; import com.wasteofplastic.askyblock.util.VaultHelper; /** * Handles warping in ASkyBlock Players can add one sign * * @author tastybento * */ public class WarpSigns implements Listener { private final ASkyBlock plugin; // Map of all warps stored as player, warp sign Location private final Map<UUID, Location> warpList = new HashMap<>(); // Where warps are stored private YamlConfiguration welcomeWarps; /** * @param plugin - ASkyBlock plugin object */ public WarpSigns(ASkyBlock plugin) { this.plugin = plugin; } /** * Checks to see if a sign has been broken * @param e - event */ @EventHandler(priority = EventPriority.NORMAL) public void onSignBreak(BlockBreakEvent e) { Block b = e.getBlock(); Player player = e.getPlayer(); if (b.getWorld().equals(ASkyBlock.getIslandWorld()) || b.getWorld().equals(ASkyBlock.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.myLocale().warpswelcomeLine)) { // 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.myLocale(player.getUniqueId()).warpsremoved); 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.myLocale(player.getUniqueId()).warpserrorNoRemove); e.setCancelled(true); } } } } } } } /** * Event handler for Sign Changes * * @param e - event */ @EventHandler(priority = EventPriority.NORMAL) public void onSignWarpCreate(SignChangeEvent e) { //plugin.getLogger().info("DEBUG: SignChangeEvent called"); String title = e.getLine(0); Player player = e.getPlayer(); if (player.getWorld().equals(ASkyBlock.getIslandWorld()) || player.getWorld().equals(ASkyBlock.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.myLocale().warpswelcomeLine)) { //plugin.getLogger().info("DEBUG: Welcome sign detected"); // Welcome sign detected - check permissions if (!(VaultHelper.checkPerm(player, Settings.PERMPREFIX + "island.addwarp"))) { Util.sendMessage(player, ChatColor.RED + plugin.myLocale(player.getUniqueId()).warpserrorNoPerm); return; } if(Settings.warpLevelsRestriction > 0 && !(ASkyBlockAPI.getInstance().getLongIslandLevel(player.getUniqueId()) > Settings.warpLevelsRestriction)){ Util.sendMessage(player, ChatColor.RED + plugin.myLocale(player.getUniqueId()).warpserrorNotEnoughLevel); return; } // Check that the player is on their island if (!(plugin.getGrid().playerIsOnIsland(player, Settings.coopsCanCreateWarps))) { Util.sendMessage(player, ChatColor.RED + plugin.myLocale(player.getUniqueId()).warpserrorNoPlace); e.setLine(0, ChatColor.RED + plugin.myLocale().warpswelcomeLine); 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.myLocale(player.getUniqueId()).warpssuccess); e.setLine(0, ChatColor.GREEN + plugin.myLocale().warpswelcomeLine); for (int i = 1; i<4; i++) { e.setLine(i, ChatColor.translateAlternateColorCodes('&', e.getLine(i))); } } else { Util.sendMessage(player, ChatColor.RED + plugin.myLocale(player.getUniqueId()).warpserrorDuplicate); e.setLine(0, ChatColor.RED + plugin.myLocale().warpswelcomeLine); 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.myLocale().warpswelcomeLine)) { //plugin.getLogger().info("DEBUG: Old sign had a green welcome"); oldSign.setLine(0, ChatColor.RED + plugin.myLocale().warpswelcomeLine); oldSign.update(true, false); Util.sendMessage(player, ChatColor.RED + plugin.myLocale(player.getUniqueId()).warpsdeactivate); 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.myLocale(player.getUniqueId()).warpssuccess); e.setLine(0, ChatColor.GREEN + plugin.myLocale().warpswelcomeLine); } else { Util.sendMessage(player, ChatColor.RED + plugin.myLocale(player.getUniqueId()).warpserrorDuplicate); e.setLine(0, ChatColor.RED + plugin.myLocale().warpswelcomeLine); } } } } } } /** * Saves the warp lists to file */ public void saveWarpList(boolean async) { if (welcomeWarps == null) { return; } //plugin.getLogger().info("Saving warps..."); final HashMap<String, Object> warps = new HashMap<String, Object>(); for (UUID p : warpList.keySet()) { warps.put(p.toString(), Util.getStringLocation(warpList.get(p))); } welcomeWarps.set("warps", warps); Util.saveYamlFile(welcomeWarps, "warps.yml", async); } /** * Creates the warp list if it does not exist */ public void loadWarpList() { plugin.getLogger().info("Loading warps..."); // warpList.clear(); welcomeWarps = Util.loadYamlFile("warps.yml"); if (welcomeWarps.getConfigurationSection("warps") == null) { welcomeWarps.createSection("warps"); // This is only used to create // the warp.yml file so forgive // this code } HashMap<String, Object> temp = (HashMap<String, Object>) welcomeWarps.getConfigurationSection("warps").getValues(true); for (String s : temp.keySet()) { try { final UUID playerUUID = UUID.fromString(s); Location l = Util.getLocationString((String) temp.get(s)); if (l != null) { warpList.put(playerUUID, l); } } catch (Exception e) { plugin.getLogger().severe("Problem loading warp at location " + temp.get(s) + " - removing."); e.printStackTrace(); } } } /** * Stores warps in the warp array * * @param playerUUID - the player's UUID * @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 warpList.remove(playerUUID); warpList.put(playerUUID, loc); saveWarpList(true); // Update warp signs // Run one tick later because text gets updated at the end of tick plugin.getServer().getScheduler().runTask(plugin, () -> { plugin.getWarpPanel().addWarp(playerUUID); 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); // Update warp signs // Run one tick later because text gets updated at the end of tick plugin.getWarpPanel().updatePanel(); } saveWarpList(true); } /** * 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.myLocale().warpswelcomeLine)) { s.setLine(0, ChatColor.RED + plugin.myLocale().warpswelcomeLine); s.update(true, false); } } } } /** * Removes a warp at a location. Called by WarpSigns.java. * * @param loc */ public void removeWarp(Location loc) { //plugin.getLogger().info("Asked to remove warp at " + loc); popSign(loc); Iterator<Entry<UUID, Location>> it = warpList.entrySet().iterator(); while (it.hasNext()) { Entry<UUID, Location> 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.myLocale(p.getUniqueId()).warpssignRemoved); } else { plugin.getMessages().setMessage(en.getKey(), ChatColor.RED + plugin.myLocale(en.getKey()).warpssignRemoved); } it.remove(); } } saveWarpList(true); plugin.getWarpPanel().updatePanel(); } /** * Lists all the known warps * * @return String set of warps */ public Set<UUID> listWarps() { // Check if any of the warp locations are null // Check if the location of the warp still exists, if not, delete it warpList.entrySet().removeIf(en -> en.getValue() == null); return warpList.keySet(); } /** * @return Sorted list of warps with most recent players listed first */ public Collection<UUID> listSortedWarps() { // Bigger value of time means a more recent login TreeMap<Long, UUID> map = new TreeMap<>(); Iterator<Entry<UUID, Location>> it = warpList.entrySet().iterator(); while (it.hasNext()) { Entry<UUID, Location> 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<UUID> 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 player's UUID * - 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 plugin.getPlayers().getName(playerUUID); } } return ""; } }