/*******************************************************************************
* 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.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.BlockFace;
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;
private final static boolean DEBUG = false;
// Map of all warps stored as player, warp sign Location
private HashMap<UUID, Location> warpList = new HashMap<UUID, Location>();
// Where warps are stored
private YamlConfiguration welcomeWarps;
/**
* @param plugin
*/
public WarpSigns(ASkyBlock plugin) {
this.plugin = plugin;
this.warpList = new HashMap<UUID, Location>();
}
/**
* 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(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
*/
@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(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(!(ASkyBlockAPI.getInstance().getIslandLevel(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))) {
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();
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() {
if (warpList == null || 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");
// Update the warp panel - needs to be done 1 tick later so that the sign
// text will be updated.
/*
if (reloadPanel) {
// This is not done on shutdown
if (Settings.useWarpPanel && plugin.getWarpPanel() != null) {
plugin.getServer().getScheduler().runTask(plugin, new Runnable() {
@Override
public void run() {
plugin.getWarpPanel().;
}});
}
}*/
//plugin.getLogger().info("End of saving warps");
}
/**
* 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 {
UUID playerUUID = UUID.fromString(s);
if (playerUUID != null) {
Location l = Util.getLocationString((String) temp.get(s));
//plugin.getLogger().info("DEBUG: Loading warp at " + l);
Block b = l.getBlock();
// Check that a warp sign is still there
if (b.getType().equals(Material.SIGN_POST) || b.getType().equals(Material.WALL_SIGN)) {
warpList.put(playerUUID, l);
} else {
plugin.getLogger().warning("Warp at location " + temp.get(s) + " has no sign - removing.");
// Test code
if (DEBUG) {
String name = plugin.getTinyDB().getPlayerName(playerUUID);
warpList.put(playerUUID, l);
b.getRelative(BlockFace.DOWN).setType(Material.DIRT);
b.setType(Material.SIGN_POST);
Sign sign = (Sign)b.getState();
sign.setLine(0, ChatColor.GREEN + plugin.myLocale().warpswelcomeLine);
sign.setLine(1, name);
sign.setLine(2, "Test 2");
sign.update();
}
// End test code
}
}
} 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
* @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.myLocale().warpswelcomeLine)) {
s.setLine(0, ChatColor.RED + plugin.myLocale().warpswelcomeLine);
s.update();
}
}
}
}
/**
* 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();
plugin.getWarpPanel().updatePanel();
}
/**
* Lists all the known warps
*
* @return String set of warps
*/
public Set<UUID> listWarps() {
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<Long, UUID>();
for (UUID uuid : warpList.keySet()) {
// 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 warp requested
* @return Location of warp
*/
public Location getWarp(UUID playerUUID) {
if (playerUUID != null && warpList.containsKey(playerUUID)) {
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 "";
}
}