/******************************************************************************* * 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.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; 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.Chunk; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Boat; import org.bukkit.entity.Entity; import org.bukkit.entity.Monster; import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; import org.bukkit.material.MaterialData; import org.bukkit.material.SimpleAttachableMaterialData; import org.bukkit.material.TrapDoor; import org.bukkit.util.Vector; import com.wasteofplastic.askyblock.Island.SettingsFlag; import com.wasteofplastic.askyblock.events.IslandChangeOwnerEvent; import com.wasteofplastic.askyblock.events.IslandPreTeleportEvent; import com.wasteofplastic.askyblock.util.Util; import com.wasteofplastic.askyblock.util.teleport.SafeTeleportBuilder; /** * This class manages the island islandGrid. It knows where every island is, and * where new * ones should go. It can handle any size of island or protection size * The islandGrid is stored in a YML file. * * @author tastybento */ public class GridManager { private static final String SETTINGS_KEY = "settingskey"; private static final String ISLANDS_FILENAME = "islands.yml"; private static final String ISLANDNAMES_FILENAME = "islandnames.yml"; private final ASkyBlock plugin; // 2D islandGrid of islands, x,z private TreeMap<Integer, TreeMap<Integer, Island>> islandGrid = new TreeMap<>(); // Reverse lookup for owner, if they exists private final HashMap<UUID, Island> ownershipMap = new HashMap<>(); private Island spawn; private final YamlConfiguration islandNames = new YamlConfiguration(); /** * @param plugin - ASkyBlock plugin object */ public GridManager(ASkyBlock plugin) { this.plugin = plugin; loadGrid(); } private void loadGrid() { plugin.getLogger().info("Loading island grid..."); islandGrid.clear(); File islandNameFile = new File(plugin.getDataFolder(), ISLANDNAMES_FILENAME); if (!islandNameFile.exists()) { try { islandNameFile.createNewFile(); } catch (IOException e) { plugin.getLogger().severe("Could not create " + ISLANDNAMES_FILENAME + "!"); } } try { islandNames.load(islandNameFile); } catch (Exception e) { //e.printStackTrace(); plugin.getLogger().severe("Could not load " + ISLANDNAMES_FILENAME); } File islandFile = new File(plugin.getDataFolder(), ISLANDS_FILENAME); if (!islandFile.exists()) { // check if island folder exists plugin.getLogger().info(ISLANDS_FILENAME + " does not exist. Creating..."); convert(); plugin.getLogger().info(ISLANDS_FILENAME + " created."); } else { plugin.getLogger().info("Loading " + ISLANDS_FILENAME); YamlConfiguration islandYaml = new YamlConfiguration(); try { islandYaml.load(islandFile); List<String> islandList = new ArrayList<>(); if (islandYaml.contains(Settings.worldName)) { // Load the island settings key List<String> settingsKey = islandYaml.getStringList(SETTINGS_KEY); // Load spawn, if it exists - V3.0.6 onwards if (islandYaml.contains("spawn")) { Location spawnLoc = Util.getLocationString(islandYaml.getString("spawn.location")); // Validate entries if (spawnLoc != null && spawnLoc.getWorld() != null && spawnLoc.getWorld().equals(ASkyBlock.getIslandWorld())) { Location spawnPoint = Util.getLocationString(islandYaml.getString("spawn.spawnpoint")); int range = islandYaml.getInt("spawn.range", Settings.islandProtectionRange); if (range < 0) { range = Settings.islandProtectionRange; } String spawnSettings = islandYaml.getString("spawn.settings"); // Make the spawn Island newSpawn = new Island(plugin, spawnLoc.getBlockX(), spawnLoc.getBlockZ()); newSpawn.setSpawn(true); if (spawnPoint != null) newSpawn.setSpawnPoint(spawnPoint); newSpawn.setProtectionSize(range); newSpawn.setSettings(spawnSettings, settingsKey); spawn = newSpawn; } } // Load the islands islandList = islandYaml.getStringList(Settings.worldName); for (String island : islandList) { Island newIsland = addIsland(island, settingsKey); if (newIsland.getOwner() != null) { ownershipMap.put(newIsland.getOwner(), newIsland); } if (newIsland.isSpawn()) { spawn = newIsland; } } } else { plugin.getLogger().severe("Could not find any islands for this world. World name in config.yml is probably wrong."); plugin.getLogger().severe("Making backup of " + ISLANDS_FILENAME + ". Correct world name and then replace " + ISLANDS_FILENAME); File rename = new File(plugin.getDataFolder(), "islands_backup.yml"); islandFile.renameTo(rename); } } catch (Exception e) { //e.printStackTrace(); plugin.getLogger().severe("Could not load " + ISLANDS_FILENAME); } } // for (int x : protectionGrid.) // plugin.getLogger().info("Debug: protection grid is size " + // protectionGrid.size()); // plugin.getLogger().info("Debug: Island grid is sized = " + // islandGrid.size()); } /** * Provides confirmation that the island is on the grid lines * * @param loc - location to check * @return true if on grid, false if not */ public boolean onGrid(Location loc) { int x = loc.getBlockX(); int z = loc.getBlockZ(); return onGrid(x, z); } public boolean onGrid(int x, int z) { if ((x - Settings.islandXOffset) % Settings.islandDistance != 0) { return false; } return (z - Settings.islandZOffset) % Settings.islandDistance == 0; } /** * Converts from the old version where islands were stored in an island * folder. * Did not work for large installations. */ private void convert() { // Read spawn file if it exists final File spawnFile = new File(plugin.getDataFolder(), "spawn.yml"); if (spawnFile.exists()) { YamlConfiguration spawn = new YamlConfiguration(); try { spawn.load(spawnFile); int range = spawn.getInt("spawn.range"); // plugin.getLogger().info("DEBUG:" + range + " " + // spawn.getString("spawn.bedrock","")); Location spawnLoc = Util.getLocationString(spawn.getString("spawn.bedrock", "")); if (spawnLoc != null && onGrid(spawnLoc)) { Island newIsland = addIsland(spawnLoc.getBlockX(), spawnLoc.getBlockZ()); setSpawn(newIsland); newIsland.setProtectionSize(range); } else { plugin.getLogger().severe("Spawn could not be imported! Location " + spawnLoc); plugin.getLogger().severe("Go to the spawn island and set it manually"); } } catch (Exception e) { plugin.getLogger().severe("Spawn could not be imported! File could not load."); } } // Go through player folder final File playerFolder = new File(plugin.getDataFolder() + File.separator + "players"); final File quarantineFolder = new File(plugin.getDataFolder() + File.separator + "quarantine"); YamlConfiguration playerFile = new YamlConfiguration(); int noisland = 0; int inTeam = 0; int count = 0; if (playerFolder.exists() && playerFolder.listFiles().length > 0) { plugin.getLogger().warning("Reading player folder..."); if (playerFolder.listFiles().length > 5000) { plugin.getLogger().warning("This could take some time with a large number of islands..."); } for (File f : playerFolder.listFiles()) { // Need to remove the .yml suffix String fileName = f.getName(); if (fileName.endsWith(".yml")) { try { playerFile.load(f); boolean hasIsland = playerFile.getBoolean("hasIsland", false); if (hasIsland) { String islandLocation = playerFile.getString("islandLocation"); if (islandLocation.isEmpty()) { plugin.getLogger().severe("Problem with " + fileName); plugin.getLogger().severe("Owner :" + playerFile.getString("playerName", "Unknown")); plugin.getLogger().severe("Player file says they have an island, but there is no location."); // Move to quarantine if (!quarantineFolder.exists()) { quarantineFolder.mkdir(); } // Move the file plugin.getLogger().severe("Moving " + f.getName() + " to " + quarantineFolder.getName()); File rename = new File(quarantineFolder, f.getName()); f.renameTo(rename); } else { // Location exists Location islandLoc = Util.getLocationString(islandLocation); if (islandLoc != null) { // Check to see if this island is already loaded Island island = getIslandAt(islandLoc); if (island != null) { // PlayerIsland exists, compare creation dates plugin.getLogger().severe("Problem with " + fileName); plugin.getLogger().severe("Owner :" + playerFile.getString("playerName", "Unknown")); plugin.getLogger().severe("This island location already exists and is already imported"); if (island.getUpdatedDate() > f.lastModified()) { plugin.getLogger().severe("Previous file is more recent so keeping it."); // Original file is more recent // Move to quarantine if (!quarantineFolder.exists()) { quarantineFolder.mkdir(); } plugin.getLogger().severe( "Moving " + (playerFile.getString("playerName", "Unknown")) + "'s file (" + f.getName() + ") to " + quarantineFolder.getName()); File rename = new File(quarantineFolder, f.getName()); f.renameTo(rename); } else { // New file is more recent plugin.getLogger().severe(playerFile.getString("playerName", "Unknown") + "'s file is more recent"); File oldFile = new File(playerFolder, island.getOwner().toString() + ".yml"); File rename = new File(quarantineFolder, oldFile.getName()); // Move to quarantine if (!quarantineFolder.exists()) { quarantineFolder.mkdir(); } plugin.getLogger().severe("Moving previous file (" + oldFile.getName() + ") to " + quarantineFolder.getName()); oldFile.renameTo(rename); deleteIsland(islandLoc); island = null; } } if (island == null) { if (!onGrid(islandLoc)) { plugin.getLogger().severe("Problem with " + fileName); plugin.getLogger().severe("Owner :" + playerFile.getString("playerName", "Unknown")); plugin.getLogger().severe("Island is not on grid lines! " + islandLoc); } String ownerString = fileName.substring(0, fileName.length() - 4); // Add the island UUID owner = UUID.fromString(ownerString); Island newIsland = addIsland(islandLoc.getBlockX(), islandLoc.getBlockZ(), owner); ownershipMap.put(owner, newIsland); // Grab when this was last updated newIsland.setUpdatedDate(f.lastModified()); if ((count) % 1000 == 0) { plugin.getLogger().info("Converted " + count + " islands"); } count++; // plugin.getLogger().info("Converted island at " // + islandLoc); // Top ten int islandLevel = playerFile.getInt("islandLevel", 0); String teamLeaderUUID = playerFile.getString("teamLeader", ""); if (islandLevel > 0) { if (!playerFile.getBoolean("hasTeam")) { plugin.getTopTen().topTenAddEntry(owner, islandLevel); } else if (!teamLeaderUUID.isEmpty()) { if (teamLeaderUUID.equals(ownerString)) { plugin.getTopTen().topTenAddEntry(owner, islandLevel); } } } // Check if there is an island info string and see if it jibes String islandInfo = playerFile.getString("islandInfo",""); if (!islandInfo.isEmpty()) { String[] split = islandInfo.split(":"); try { //int protectionRange = Integer.parseInt(split[3]); //int islandDistance = Integer.parseInt(split[4]); newIsland.setLocked(false); if (split.length > 6) { // Get locked status if (split[6].equalsIgnoreCase("true")) { newIsland.setLocked(true); } } // Check if deletable newIsland.setPurgeProtected(false); if (split.length > 7) { if (split[7].equalsIgnoreCase("true")) { newIsland.setPurgeProtected(true); } } if (!split[5].equals("null")) { if (split[5].equals("spawn")) { newIsland.setSpawn(true); // Try to get the spawn point if (split.length > 8) { //plugin.getLogger().info("DEBUG: " + serial.substring(serial.indexOf(":SP:") + 4)); Location spawnPoint = Util.getLocationString(islandInfo.substring(islandInfo.indexOf(":SP:") + 4)); newIsland.setSpawnPoint(spawnPoint); } } } // Check if protection options there if (!newIsland.isSpawn()) { //plugin.getLogger().info("DEBUG: NOT SPAWN owner is " + owner + " location " + center); if (split.length > 8 && split[8].length() == 29) { // Parse the 8th string into island guard protection settings int index = 0; // Run through the enum and set for (SettingsFlag flag : SettingsFlag.values()) { if (index < split[8].length()) { newIsland.setIgsFlag(flag, split[8].charAt(index++) == '1'); } } } } } catch (Exception e) { e.printStackTrace(); } } } } else { plugin.getLogger().severe("Problem with " + fileName); plugin.getLogger().severe("Owner :" + playerFile.getString("playerName", "Unknown")); plugin.getLogger().severe("The world for this file does not exist!"); } } } else { noisland++; if (playerFile.getBoolean("hasTeam", false)) { inTeam++; } } } catch (Exception e) { plugin.getLogger().severe("Problem with " + fileName); //e.printStackTrace(); } } } plugin.getLogger().info("Converted " + count + " islands from player's folder"); plugin.getLogger().info(noisland + " have no island, of which " + inTeam + " are in a team."); plugin.getLogger().info((noisland - inTeam) + " are in the system, but have no island or team"); } int count2 = 0; // Check island folder final File islandFolder = new File(plugin.getDataFolder() + File.separator + "islands"); if (islandFolder.exists() && islandFolder.listFiles().length > 0) { plugin.getLogger().warning("Reading island folder..."); if (islandFolder.listFiles().length > 5000) { plugin.getLogger().warning("This could take some time with a large number of islands..."); } for (File f : islandFolder.listFiles()) { // Need to remove the .yml suffix String fileName = f.getName(); int comma = fileName.indexOf(","); if (fileName.endsWith(".yml") && comma != -1) { try { // Parse to an island value int x = Integer.parseInt(fileName.substring(0, comma)); int z = Integer.parseInt(fileName.substring(comma + 1, fileName.indexOf("."))); if (!onGrid(x, z)) { plugin.getLogger().severe("Island is not on grid lines! " + x + "," + z + " skipping..."); } else { // Note that this is the CENTER of the island if (getIslandAt(x, z) == null) { addIsland(x, z); if (count2 % 1000 == 0) { plugin.getLogger().info("Converted " + count + " islands"); } count2++; // plugin.getLogger().info("Added island from island folder: " // + x + "," +z); } } } catch (Exception e) { e.printStackTrace(); } } } plugin.getLogger().info("Converted " + count2 + " islands from island folder"); plugin.getLogger().info("Total " + (count + count2) + " islands converted."); } // Now save the islandGrid saveGrid(); } /** * Saves the grid asynchronously */ public void saveGrid() { saveGrid(true); } /** * Saves the grid. Option to save sync or async. * Async cannot be used when disabling the plugin * @param async - true if saving should be done async */ public void saveGrid(boolean async) { //final File islandFile = new File(plugin.getDataFolder(), ISLANDS_FILENAME); final YamlConfiguration islandYaml = new YamlConfiguration(); // Save the settings config key List<String> islandSettings = new ArrayList<String>(); for (SettingsFlag flag: SettingsFlag.values()) { islandSettings.add(flag.toString()); } islandYaml.set(SETTINGS_KEY, islandSettings); // Save spawn if (getSpawn() != null) { islandYaml.set("spawn.location", Util.getStringLocation(getSpawn().getCenter())); islandYaml.set("spawn.spawnpoint", Util.getStringLocation(getSpawn().getSpawnPoint())); islandYaml.set("spawn.range", getSpawn().getProtectionSize()); islandYaml.set("spawn.settings", getSpawn().getSettings()); } // Save the regular islands List<String> islandList = new ArrayList<String>(); Iterator<TreeMap<Integer, Island>> it = islandGrid.values().iterator(); while (it.hasNext()) { Iterator<Island> islandIt = it.next().values().iterator(); while (islandIt.hasNext()) { Island island = islandIt.next(); if (!island.isSpawn()) { islandList.add(island.save()); } } } islandYaml.set(Settings.worldName, islandList); // Save the file Util.saveYamlFile(islandYaml, ISLANDS_FILENAME, async); // Save any island names if (islandNames != null) { Util.saveYamlFile(islandNames, ISLANDNAMES_FILENAME, async); } } /** * Returns the island at the location or null if there is none. * This includes the full island space, not just the protected area * * @param location - location to query * @return PlayerIsland object */ public Island getIslandAt(Location location) { if (location == null) { return null; } // World check if (!inWorld(location)) { return null; } // Check if it is spawn if (spawn != null && spawn.onIsland(location)) { return spawn; } return getIslandAt(location.getBlockX(), location.getBlockZ()); } /** * Determines if a location is in the island world or not or * in the new nether if it is activated * @param loc - location to query * @return true if in the island world */ protected boolean inWorld(Location loc) { if (loc.getWorld().equals(ASkyBlock.getIslandWorld())) { return true; } return Settings.createNether && Settings.newNether && ASkyBlock.getNetherWorld() != null && loc.getWorld().equals(ASkyBlock.getNetherWorld()); } /** * Returns the island at the x,z location or null if there is none. * This includes the full island space, not just the protected area. * * @param x coord * @param z coord * @return PlayerIsland or null */ public Island getIslandAt(int x, int z) { Entry<Integer, TreeMap<Integer, Island>> en = islandGrid.floorEntry(x); if (en != null) { Entry<Integer, Island> ent = en.getValue().floorEntry(z); if (ent != null) { // Check if in the island range Island island = ent.getValue(); if (island.inIslandSpace(x, z)) { // plugin.getLogger().info("DEBUG: In island space"); return island; } //plugin.getLogger().info("DEBUG: not in island space"); } } return null; } /** * Returns the island being public at the location or null if there is none * * @param location - location to query * @return Island object */ public Island getProtectedIslandAt(Location location) { //plugin.getLogger().info("DEBUG: getProtectedIslandAt " + location); // Try spawn if (spawn != null && spawn.onIsland(location)) { return spawn; } Island island = getIslandAt(location); if (island == null) { //plugin.getLogger().info("DEBUG: no island at this location"); return null; } if (island.onIsland(location)) { return island; } return null; } /** * Returns the owner of the island at location or null if there is none * * @param location location to query * @return UUID of owner */ public UUID getOwnerOfIslandAt(Location location) { Island island = getIslandAt(location); if (island != null) { return island.getOwner(); } return null; } // islandGrid manipulation methods /** * Adds an island to the islandGrid with the CENTER point x,z * * @param x cood * @param z cood * @return island object */ public Island addIsland(int x, int z) { return addIsland(x, z, null); } /** * Adds an island to the islandGrid with the center point x,z owner UUID * * @param x coord * @param z coord * @param owner owner of island * @return island object */ public Island addIsland(int x, int z, UUID owner) { // Check if this owner already has an island if (ownershipMap.containsKey(owner)) { // Island exists Island island = ownershipMap.get(owner); // Remove island if the player already has a different one if (island.getCenter().getBlockX() != x || island.getCenter().getBlockZ() != z) { //plugin.getLogger().warning( //"Island at " + island.getCenter().getBlockX() + ", " + island.getCenter().getBlockZ() //+ " is already owned by this player. Removing ownership of this island."); island.setOwner(null); ownershipMap.remove(owner); } else { // Player already has island addToGrids(island); return island; } } // plugin.getLogger().info("DEBUG: adding island to grid at " + x + ", " // + z + " for " + owner.toString()); Island newIsland = new Island(plugin, x, z, owner); // if (newIsland != null) { // plugin.getLogger().info("DEBUG: new island is good"); // } addToGrids(newIsland); return newIsland; } /** * Adds island to the grid using the stored information * * @param islandSerialized serialized version of the island information * @param settingsKey * @return island object */ public Island addIsland(String islandSerialized, List<String> settingsKey) { // plugin.getLogger().info("DEBUG: adding island " + islandSerialized); Island newIsland = new Island(plugin, islandSerialized, settingsKey); addToGrids(newIsland); return newIsland; } /** * Adds an island to the grid register * @param newIsland new island object to register on the grid */ private void addToGrids(Island newIsland) { //plugin.getLogger().info("DEBUG: adding island to grid at " + newIsland.getMinX() + "," + newIsland.getMinZ()); if (newIsland.getOwner() != null) { ownershipMap.put(newIsland.getOwner(), newIsland); } if (islandGrid.containsKey(newIsland.getMinX())) { //plugin.getLogger().info("DEBUG: min x is in the grid :" + newIsland.getMinX()); TreeMap<Integer, Island> zEntry = islandGrid.get(newIsland.getMinX()); if (zEntry.containsKey(newIsland.getMinZ())) { //plugin.getLogger().info("DEBUG: min z is in the grid :" + newIsland.getMinZ()); // Island already exists Island conflict = islandGrid.get(newIsland.getMinX()).get(newIsland.getMinZ()); plugin.getLogger().warning("*** Duplicate or overlapping islands! ***"); plugin.getLogger().warning( "Island at (" + newIsland.getCenter().getBlockX() + ", " + newIsland.getCenter().getBlockZ() + ") conflicts with (" + conflict.getCenter().getBlockX() + ", " + conflict.getCenter().getBlockZ() + ")"); if (conflict.getOwner() != null) { plugin.getLogger().warning("Accepted island is owned by " + plugin.getPlayers().getName(conflict.getOwner())); plugin.getLogger().warning(conflict.getOwner().toString() + ".yml"); } else { plugin.getLogger().warning("Accepted island is unowned."); } if (newIsland.getOwner() != null) { plugin.getLogger().warning("Denied island is owned by " + plugin.getPlayers().getName(newIsland.getOwner())); plugin.getLogger().warning(newIsland.getOwner().toString() + ".yml"); } else { plugin.getLogger().warning("Denied island is unowned and was just found in the islands folder. Skipping it..."); } plugin.getLogger().warning("Recommend that the denied player file is deleted otherwise weird things can happen."); } else { // Add island //plugin.getLogger().info("DEBUG: added island to grid at " + newIsland.getMinX() + "," + newIsland.getMinZ()); zEntry.put(newIsland.getMinZ(), newIsland); islandGrid.put(newIsland.getMinX(), zEntry); // plugin.getLogger().info("Debug: " + newIsland.toString()); } } else { // Add island //plugin.getLogger().info("DEBUG: added island to grid at " + newIsland.getMinX() + "," + newIsland.getMinZ()); TreeMap<Integer, Island> zEntry = new TreeMap<Integer, Island>(); zEntry.put(newIsland.getMinZ(), newIsland); islandGrid.put(newIsland.getMinX(), zEntry); } } /** * Deletes any island owned by owner from the grid. Does not actually remove the island * from the world. Used for cleaning up issues such as mismatches between player files * and island.yml * @param owner UUID of owner */ public void deleteIslandOwner(UUID owner) { if (owner != null && ownershipMap.containsKey(owner)) { Island island = ownershipMap.get(owner); if (island != null) { island.setOwner(null); } ownershipMap.remove(owner); } } /** * Removes the island at location loc from the grid and removes the player * from the ownership map * * @param loc location to remove */ public void deleteIsland(Location loc) { // plugin.getLogger().info("DEBUG: deleting island at " + loc); Island island = getIslandAt(loc); if (island != null) { UUID owner = island.getOwner(); int x = island.getMinX(); int z = island.getMinZ(); // plugin.getLogger().info("DEBUG: x = " + x + " z = " + z); if (islandGrid.containsKey(x)) { // plugin.getLogger().info("DEBUG: x found"); TreeMap<Integer, Island> zEntry = islandGrid.get(x); if (zEntry.containsKey(z)) { // plugin.getLogger().info("DEBUG: z found - deleting the island"); // Island exists - delete it Island deletedIsland = zEntry.get(z); deletedIsland.setOwner(null); deletedIsland.setLocked(false); zEntry.remove(z); islandGrid.put(x, zEntry); } // else { // plugin.getLogger().info("DEBUG: could not find z"); // } } // Remove from the ownership map // If the owner already has been given a new island, then this will // not be needed if (owner != null && ownershipMap.containsKey(owner)) { if (ownershipMap.get(owner).equals(island)) { ownershipMap.remove(owner); } } } } /** * Gets island by owner's UUID. Just because the island does not exist in * this map * does not mean it does not exist in this world, due to legacy island * support * Will return the island that this player is a member of if a team player * * @param owner island owner's UUID * @return island object or null if it does not exist in the list */ public Island getIsland(UUID owner) { if (owner != null) { if (ownershipMap.containsKey(owner)) { return ownershipMap.get(owner); } // Try and get team islands UUID leader = plugin.getPlayers().getTeamLeader(owner); if (leader != null && ownershipMap.containsKey(leader)) { return ownershipMap.get(leader); } } return null; } /** * Sets an island to be owned by another player. If the new owner had an * island, that island is released to null ownership * * @param island island object * @param newOwner new owner's UUID */ public void setIslandOwner(Island island, UUID newOwner) { // The old owner UUID oldOwner = island.getOwner(); // If the island owner is being set to null - remove the old owner's // ownership if (newOwner == null && oldOwner != null) { ownershipMap.remove(oldOwner); island.setOwner(null); return; } // Check if the new owner already has an island if (ownershipMap.containsKey(newOwner)) { Island oldIsland = ownershipMap.get(newOwner); // plugin.getLogger().warning("Island at " + // oldIsland.getCenter().getBlockX() + ", " + // oldIsland.getCenter().getBlockZ() // + // " is already owned by this player. Removing ownership of this island."); oldIsland.setOwner(null); ownershipMap.remove(newOwner); } // Make the new owner own the island if (newOwner != null && island != null) { // See if this island has an owner already island.setOwner(newOwner); // If the old owner exists remove them from the map if (oldOwner != null) { // Remove the old entry ownershipMap.remove(oldOwner); } // Insert the new entry ownershipMap.put(newOwner, island); } } /** * @return the ownershipMap */ public HashMap<UUID, Island> getOwnershipMap() { return ownershipMap; } /** * @return the spawn or null if spawn does not exist */ public Island getSpawn() { return spawn; } /** * @param spawn * the spawn to set */ public void setSpawn(Island spawn) { // plugin.getLogger().info("DEBUG: Spawn set"); spawn.setSpawn(true); spawn.setProtectionSize(spawn.getIslandDistance()); this.spawn = spawn; } public void deleteSpawn() { deleteIsland(spawn.getCenter()); this.spawn = null; } /** * Indicates whether a player is at the island spawn or not * * @param playerLoc - location to query * @return true if they are, false if they are not, or spawn does not exist */ public boolean isAtSpawn(Location playerLoc) { if (spawn == null) { return false; } return spawn.onIsland(playerLoc); } /** * Determines if an island is at a location in this area * location. Also checks if the spawn island is in this area. * Used for creating new islands ONLY * * @param loc location to query * @return true if found, otherwise false */ public boolean islandAtLocation(Location loc) { if (loc == null) { return true; } // Make sure location is on the grid loc = getClosestIsland(loc); // getLogger().info("DEBUG checking islandAtLocation for location " + // loc.toString()); // Check the island grid if (getIslandAt(loc) != null) { // This checks if loc is inside the island spawn radius too return true; } final int px = loc.getBlockX(); final int pz = loc.getBlockZ(); // Extra spawn area check // If island protection distance is less than island distance then the // check above will cover it // Island edge must be > protection edge spawn Island spawn = getSpawn(); if (spawn != null && spawn.getProtectionSize() > spawn.getIslandDistance()) { if (Math.abs(px - spawn.getCenter().getBlockX()) < ((spawn.getProtectionSize() + Settings.islandDistance) / 2) && Math.abs(pz - spawn.getCenter().getBlockZ()) < ((spawn.getProtectionSize() + Settings.islandDistance) / 2)) { // getLogger().info("DEBUG: island is within spawn space " + px // + " " + pz); return true; } } if (!Settings.useOwnGenerator) { // Block check if (!loc.getBlock().isEmpty() && !loc.getBlock().isLiquid()) { // Get the closest island plugin.getLogger().info("Found solid block at island height - adding to " + ISLANDS_FILENAME + " " + px + "," + pz); addIsland(px, pz); return true; } // Look around for (int x = -5; x <= 5; x++) { for (int y = 10; y <= 255; y++) { for (int z = -5; z <= 5; z++) { if (!loc.getWorld().getBlockAt(x + px, y, z + pz).isEmpty() && !loc.getWorld().getBlockAt(x + px, y, z + pz).isLiquid()) { plugin.getLogger().info("Solid block found during long search - adding to " + ISLANDS_FILENAME + " " + px + "," + pz); addIsland(px, pz); return true; } } } } } return false; } /** * This returns the coordinate of where an island should be on the grid. * * @param location location to query * @return Location of closest island */ public Location getClosestIsland(Location location) { long x = Math.round((double) location.getBlockX() / Settings.islandDistance) * Settings.islandDistance + Settings.islandXOffset; long z = Math.round((double) location.getBlockZ() / Settings.islandDistance) * Settings.islandDistance + Settings.islandZOffset; long y = Settings.islandHeight; return new Location(location.getWorld(), x, y, z); } /** * Checks if this location is safe for a player to teleport to. Used by * warps and boat exits Unsafe is any liquid or air and also if there's no * space * * @param l * - Location to be checked * @return true if safe, otherwise false */ public static boolean isSafeLocation(final Location l) { if (l == null) { return false; } // TODO: improve the safe location finding. //Bukkit.getLogger().info("DEBUG: " + l.toString()); final Block ground = l.getBlock().getRelative(BlockFace.DOWN); final Block space1 = l.getBlock(); final Block space2 = l.getBlock().getRelative(BlockFace.UP); //Bukkit.getLogger().info("DEBUG: ground = " + ground.getType()); //Bukkit.getLogger().info("DEBUG: space 1 = " + space1.getType()); //Bukkit.getLogger().info("DEBUG: space 2 = " + space2.getType()); // Portals are not "safe" if (space1.getType() == Material.PORTAL || ground.getType() == Material.PORTAL || space2.getType() == Material.PORTAL || space1.getType() == Material.ENDER_PORTAL || ground.getType() == Material.ENDER_PORTAL || space2.getType() == Material.ENDER_PORTAL) { return false; } // If ground is AIR, then this is either not good, or they are on slab, // stair, etc. if (ground.getType() == Material.AIR) { // Bukkit.getLogger().info("DEBUG: air"); return false; } // In ASkyBlock, liquid may be unsafe if (ground.isLiquid() || space1.isLiquid() || space2.isLiquid()) { if (Settings.acidDamage > 0D || ground.getType().equals(Material.STATIONARY_LAVA) || ground.getType().equals(Material.LAVA) || space1.getType().equals(Material.STATIONARY_LAVA) || space1.getType().equals(Material.LAVA) || space2.getType().equals(Material.STATIONARY_LAVA) || space2.getType().equals(Material.LAVA)) { return false; } } MaterialData md = ground.getState().getData(); if (md instanceof SimpleAttachableMaterialData) { //Bukkit.getLogger().info("DEBUG: trapdoor/button/tripwire hook etc."); if (md instanceof TrapDoor) { TrapDoor trapDoor = (TrapDoor)md; if (trapDoor.isOpen()) { //Bukkit.getLogger().info("DEBUG: trapdoor open"); return false; } } else { return false; } //Bukkit.getLogger().info("DEBUG: trapdoor closed"); } if (ground.getType().equals(Material.CACTUS) || ground.getType().equals(Material.BOAT) || ground.getType().equals(Material.FENCE) || ground.getType().equals(Material.NETHER_FENCE) || ground.getType().equals(Material.SIGN_POST) || ground.getType().equals(Material.WALL_SIGN)) { // Bukkit.getLogger().info("DEBUG: cactus"); return false; } // Check that the space is not solid // The isSolid function is not fully accurate (yet) so we have to // check // a few other items // isSolid thinks that PLATEs and SIGNS are solid, but they are not if (space1.getType().isSolid() && !space1.getType().equals(Material.SIGN_POST) && !space1.getType().equals(Material.WALL_SIGN)) { return false; } return !space2.getType().isSolid() || space2.getType().equals(Material.SIGN_POST) || space2 .getType().equals(Material.WALL_SIGN); } /** * Determines a safe teleport spot on player's island or the team island * they belong to. * * @param p UUID of player * @param number - starting home location e.g., 1 * @return Location of a safe teleport spot or null if one cannot be found */ public Location getSafeHomeLocation(final UUID p, int number) { // Try the numbered home location first Location l = plugin.getPlayers().getHomeLocation(p, number); if (l == null) { // Get the default home, which may be null too, but that's okay number = 1; l = plugin.getPlayers().getHomeLocation(p, number); } // Check if it is safe //plugin.getLogger().info("DEBUG: Home location " + l); if (l != null) { // Homes are stored as integers and need correcting to be more central if (isSafeLocation(l)) { return l.clone().add(new Vector(0.5D,0,0.5D)); } // To cover slabs, stairs and other half blocks, try one block above Location lPlusOne = l.clone(); lPlusOne.add(new Vector(0, 1, 0)); if (lPlusOne != null) { if (isSafeLocation(lPlusOne)) { // Adjust the home location accordingly plugin.getPlayers().setHomeLocation(p, lPlusOne, number); return lPlusOne.clone().add(new Vector(0.5D,0,0.5D)); } } } //plugin.getLogger().info("DEBUG: Home location either isn't safe, or does not exist so try the island"); // Home location either isn't safe, or does not exist so try the island // location if (plugin.getPlayers().inTeam(p)) { l = plugin.getPlayers().getTeamIslandLocation(p); if (isSafeLocation(l)) { plugin.getPlayers().setHomeLocation(p, l, number); return l.clone().add(new Vector(0.5D,0,0.5D)); } else { // try team leader's home Location tlh = plugin.getPlayers().getHomeLocation(plugin.getPlayers().getTeamLeader(p)); if (tlh != null) { if (isSafeLocation(tlh)) { plugin.getPlayers().setHomeLocation(p, tlh, number); return tlh.clone().add(new Vector(0.5D,0,0.5D)); } } } } else { l = plugin.getPlayers().getIslandLocation(p); if (isSafeLocation(l)) { plugin.getPlayers().setHomeLocation(p, l, number); return l.clone().add(new Vector(0.5D,0,0.5D)); } } if (l == null) { plugin.getLogger().warning(plugin.getPlayers().getName(p) + " player has no island!"); return null; } //plugin.getLogger().info("DEBUG: If these island locations are not safe, then we need to get creative"); // If these island locations are not safe, then we need to get creative // Try the default location //plugin.getLogger().info("DEBUG: default"); Location dl = new Location(l.getWorld(), l.getX() + 0.5D, l.getY() + 5D, l.getZ() + 2.5D, 0F, 30F); if (isSafeLocation(dl)) { plugin.getPlayers().setHomeLocation(p, dl, number); return dl; } // Try just above the bedrock //plugin.getLogger().info("DEBUG: above bedrock"); dl = new Location(l.getWorld(), l.getX() + 0.5D, l.getY() + 5D, l.getZ() + 0.5D, 0F, 30F); if (isSafeLocation(dl)) { plugin.getPlayers().setHomeLocation(p, dl, number); return dl; } // Try all the way up to the sky //plugin.getLogger().info("DEBUG: try all the way to the sky"); for (int y = l.getBlockY(); y < 255; y++) { final Location n = new Location(l.getWorld(), l.getX() + 0.5D, y, l.getZ() + 0.5D); if (isSafeLocation(n)) { plugin.getPlayers().setHomeLocation(p, n, number); return n; } } //plugin.getLogger().info("DEBUG: unsuccessful"); // Unsuccessful return null; } /** * This is a generic scan that can work in the overworld or the nether * @param l - location around which to scan * @param i - the range to scan for a location less than 0 means the full island. * @return - safe location, or null if none can be found */ public Location bigScan(Location l, int i) { final int height; final int depth; if (i > 0) { height = i; depth = i; } else { Island island = plugin.getGrid().getIslandAt(l); if (island == null) { return null; } i = island.getProtectionSize(); height = l.getWorld().getMaxHeight() - l.getBlockY(); depth = l.getBlockY(); } //plugin.getLogger().info("DEBUG: ranges i = " + i); //plugin.getLogger().info(" " + minX + "," + minZ + " " + maxX + " " + maxZ); //plugin.getLogger().info("DEBUG: height = " + height); //plugin.getLogger().info("DEBUG: depth = " + depth); //plugin.getLogger().info("DEBUG: trying to find a safe spot at " + l.toString()); // Work outwards from l until the closest safe location is found. int minXradius = 0; int maxXradius = 0; int minZradius = 0; int maxZradius = 0; int minYradius = 0; int maxYradius = 0; do { int minX = l.getBlockX()-minXradius; int minZ = l.getBlockZ()-minZradius; int minY = l.getBlockY()-minYradius; int maxX = l.getBlockX()+maxXradius; int maxZ = l.getBlockZ()+maxZradius; int maxY = l.getBlockY()+maxYradius; for (int x = minX; x<= maxX; x++) { for (int z = minZ; z <= maxZ; z++) { for (int y = minY; y <= maxY; y++) { if (!((x > minX && x < maxX) && (z > minZ && z < maxZ) && (y > minY && y < maxY))) { //plugin.getLogger().info("DEBUG: checking " + x + "," + y + "," + z); Location ultimate = new Location(l.getWorld(), x + 0.5D, y, z + 0.5D); if (isSafeLocation(ultimate)) { //plugin.getLogger().info("DEBUG: Found! " + ultimate); return ultimate; } } } } } if (minXradius < i) { minXradius++; } if (maxXradius < i) { maxXradius++; } if (minZradius < i) { minZradius++; } if (maxZradius < i) { maxZradius++; } if (minYradius < depth) { minYradius++; } if (maxYradius < height) { maxYradius++; } //plugin.getLogger().info("DEBUG: Radii " + minXradius + "," + minYradius + "," + minZradius + // "," + maxXradius + "," + maxYradius + "," + maxZradius); } while (minXradius < i || maxXradius < i || minZradius < i || maxZradius < i || minYradius < depth || maxYradius < height); // Nothing worked return null; } /** * This teleports player to their island. If not safe place can be found * then the player is sent to spawn via /spawn command * * @param player player object * @return true if the home teleport is successful */ public void homeTeleport(final Player player) { homeTeleport(player, 1); } /** * Teleport player to a home location. If one cannot be found a search is done to * find a safe place. * @param player player object * @param number - home location to do to * @return true if successful, false if not */ @SuppressWarnings("deprecation") public void homeTeleport(final Player player, int number) { Location home = null; //plugin.getLogger().info("home teleport called for #" + number); home = getSafeHomeLocation(player.getUniqueId(), number); //plugin.getLogger().info("home get safe loc = " + home); // Check if the player is a passenger in a boat if (player.isInsideVehicle()) { Entity boat = player.getVehicle(); if (boat instanceof Boat) { player.leaveVehicle(); // Remove the boat so they don't lie around everywhere boat.remove(); player.getInventory().addItem(new ItemStack(Material.BOAT, 1)); player.updateInventory(); } } if (home == null) { //plugin.getLogger().info("Fixing home location using safe spot teleport"); // Try to fix this teleport location and teleport the player if possible new SafeTeleportBuilder(plugin) .entity(player) .location(plugin.getPlayers().getHomeLocation(player.getUniqueId(), number)) .homeNumber(number) .build(); return; } //plugin.getLogger().info("DEBUG: home loc = " + home + " teleporting"); //home.getChunk().load(); IslandPreTeleportEvent event = new IslandPreTeleportEvent(player, IslandPreTeleportEvent.Type.HOME, home); Bukkit.getPluginManager().callEvent(event); if (!event.isCancelled()) { player.teleport(event.getLocation()); //player.sendBlockChange(home, Material.GLOWSTONE, (byte)0); if (number ==1 ) { Util.sendMessage(player, ChatColor.GREEN + plugin.myLocale(player.getUniqueId()).islandteleport); } else { Util.sendMessage(player, ChatColor.GREEN + plugin.myLocale(player.getUniqueId()).islandteleport + " #" + number); } } plugin.getPlayers().setInTeleport(player.getUniqueId(), false); } /** * Sets the numbered home location based on where the player is now * @param player player object * @param number home number */ public void homeSet(Player player, int number) { // Check if player is in their home world if (!player.getWorld().equals(plugin.getPlayers().getIslandLocation(player.getUniqueId()).getWorld())) { Util.sendMessage(player, ChatColor.RED + plugin.myLocale(player.getUniqueId()).setHomeerrorNotOnIsland); return; } // Check if player is on island, ignore coops if (!plugin.getGrid().playerIsOnIsland(player, false)) { Util.sendMessage(player, ChatColor.RED + plugin.myLocale(player.getUniqueId()).setHomeerrorNotOnIsland); return; } plugin.getPlayers().setHomeLocation(player.getUniqueId(), player.getLocation(), number); if (number == 1) { Util.sendMessage(player, ChatColor.GREEN + plugin.myLocale(player.getUniqueId()).setHomehomeSet); } else { Util.sendMessage(player, ChatColor.GREEN + plugin.myLocale(player.getUniqueId()).setHomehomeSet + " #" + number); } } /** * Sets the home location based on where the player is now * * @param player player object */ public void homeSet(final Player player) { homeSet(player, 1); } /** * Checks if a player is in their full island space * @param player * @return true if they are anywhere inside their island space (not just protected area) */ public boolean inIslandSpace(Player player) { if (player == null) { return false; } Island island = getIslandAt(player.getLocation()); if (island != null) { return island.inIslandSpace(player.getLocation()) && island.getMembers() .contains(player.getUniqueId()); } return false; } /** * Checks if a specific location is within the protected range of an island * owned by the player * * @param player player object * @param loc location to query * @return true if location is on island of player */ public boolean locationIsOnIsland(final Player player, final Location loc) { if (player == null) { return false; } // Get the player's island from the grid if it exists Island island = getIslandAt(loc); if (island != null) { //plugin.getLogger().info("DEBUG: island here is " + island.getCenter()); // On an island in the grid //plugin.getLogger().info("DEBUG: onIsland = " + island.onIsland(loc)); //plugin.getLogger().info("DEBUG: members = " + island.getMembers()); //plugin.getLogger().info("DEBUG: player UUID = " + player.getUniqueId()); //plugin.getLogger().info("DEBUG: allowed"); // In a protected zone but is on the list of acceptable players // Not allowed //plugin.getLogger().info("DEBUG: not allowed"); return island.onIsland(loc) && island.getMembers().contains(player.getUniqueId()); } else { //plugin.getLogger().info("DEBUG: no island at this location"); } // Not in the grid, so do it the old way // Make a list of test locations and test them Set<Location> islandTestLocations = new HashSet<Location>(); if (plugin.getPlayers().hasIsland(player.getUniqueId())) { islandTestLocations.add(plugin.getPlayers().getIslandLocation(player.getUniqueId())); } else if (plugin.getPlayers().inTeam(player.getUniqueId())) { islandTestLocations.add(plugin.getPlayers().get(player.getUniqueId()).getTeamIslandLocation()); } // Check any coop locations islandTestLocations.addAll(CoopPlay.getInstance().getCoopIslands(player)); if (islandTestLocations.isEmpty()) { return false; } // Run through all the locations for (Location islandTestLocation : islandTestLocations) { if (loc.getWorld().equals(islandTestLocation.getWorld())) { if (loc.getX() >= islandTestLocation.getX() - Settings.islandProtectionRange / 2D && loc.getX() < islandTestLocation.getX() + Settings.islandProtectionRange / 2D && loc.getZ() >= islandTestLocation.getZ() - Settings.islandProtectionRange / 2D && loc.getZ() < islandTestLocation.getZ() + Settings.islandProtectionRange / 2D) { return true; } } } return false; } /** * Finds out if location is within a set of island locations and returns the * one that is there or null if not * * @param islandTestLocations set of test locations * @param loc location to query * @return Location found that is on the island */ public Location locationIsOnIsland(final Set<Location> islandTestLocations, final Location loc) { // Run through all the locations for (Location islandTestLocation : islandTestLocations) { if (loc.getWorld().equals(islandTestLocation.getWorld())) { if (getIslandAt(islandTestLocation) != null) { // Get the protection range for this location if possible Island island = getProtectedIslandAt(islandTestLocation); if (island != null) { // We are in a protected island area. return island.getCenter(); } } else if (loc.getX() > islandTestLocation.getX() - Settings.islandProtectionRange / 2D && loc.getX() < islandTestLocation.getX() + Settings.islandProtectionRange / 2D && loc.getZ() > islandTestLocation.getZ() - Settings.islandProtectionRange / 2D && loc.getZ() < islandTestLocation.getZ() + Settings.islandProtectionRange / 2D) { return islandTestLocation; } } } return null; } /** * Checks if an online player is in the protected area of their island, a team island or a * coop island * * @param player playe object * @return true if on valid island, false if not */ public boolean playerIsOnIsland(final Player player) { return playerIsOnIsland(player, true); } /** * Checks if an online player is in the protected area of their island, a team island or a * coop island * @param player playe object * @param coop - if true, coop islands are included * @return true if on valid island, false if not */ public boolean playerIsOnIsland(final Player player, boolean coop) { return locationIsAtHome(player, coop, player.getLocation()); } /** * Checks if a location is within the home boundaries of a player. If coop is true, this check includes coop players. * @param player player object * @param coop true if coops should be included * @param loc location to query * @return true if the location is within home boundaries */ public boolean locationIsAtHome(final Player player, boolean coop, Location loc) { // Make a list of test locations and test them Set<Location> islandTestLocations = new HashSet<Location>(); if (plugin.getPlayers().hasIsland(player.getUniqueId())) { islandTestLocations.add(plugin.getPlayers().getIslandLocation(player.getUniqueId())); // If new Nether if (Settings.createNether && Settings.newNether && ASkyBlock.getNetherWorld() != null) { islandTestLocations.add(netherIsland(plugin.getPlayers().getIslandLocation(player.getUniqueId()))); } } else if (plugin.getPlayers().inTeam(player.getUniqueId())) { islandTestLocations.add(plugin.getPlayers().getTeamIslandLocation(player.getUniqueId())); if (Settings.createNether && Settings.newNether && ASkyBlock.getNetherWorld() != null) { islandTestLocations.add(netherIsland(plugin.getPlayers().getTeamIslandLocation(player.getUniqueId()))); } } // Check coop locations if (coop) { islandTestLocations.addAll(CoopPlay.getInstance().getCoopIslands(player)); } if (islandTestLocations.isEmpty()) { return false; } // Run through all the locations for (Location islandTestLocation : islandTestLocations) { // Must be in the same world as the locations being checked // Note that getWorld can return null if a world has been deleted on the server if (islandTestLocation != null && islandTestLocation.getWorld() != null && islandTestLocation.getWorld().equals(loc.getWorld())) { int protectionRange = Settings.islandProtectionRange; if (getIslandAt(islandTestLocation) != null) { // Get the protection range for this location if possible Island island = getProtectedIslandAt(islandTestLocation); if (island != null) { // We are in a protected island area. protectionRange = island.getProtectionSize(); } } if (loc.getX() > islandTestLocation.getX() - protectionRange / 2D && loc.getX() < islandTestLocation.getX() + protectionRange / 2D && loc.getZ() > islandTestLocation.getZ() - protectionRange / 2D && loc.getZ() < islandTestLocation.getZ() + protectionRange / 2D) { return true; } } } return false; } /** * Generates a Nether version of the locations * @param islandLocation - location to generate * @return location of nether version */ private Location netherIsland(Location islandLocation) { //plugin.getLogger().info("DEBUG: netherworld = " + ASkyBlock.getNetherWorld()); return islandLocation.toVector().toLocation(ASkyBlock.getNetherWorld()); } /** * Checks to see if a player is trespassing on another player's island * Both players must be online. * * @param owner * - owner or team member of an island * @param target target of the query * @return true if they are on the island otherwise false. */ public boolean isOnIsland(final Player owner, final Player target) { // Check world if (target.getWorld().equals(ASkyBlock.getIslandWorld()) || (Settings.newNether && Settings.createNether && target.getWorld().equals(ASkyBlock.getNetherWorld()))) { // Get the island location of owner Location islandTestLocation = null; if (plugin.getPlayers().inTeam(owner.getUniqueId())) { // Is the target in the owner's team? if (plugin.getPlayers().getMembers(plugin.getPlayers().getTeamLeader(owner.getUniqueId())).contains(target.getUniqueId())) { // Yes, so this is not a trespass for sure return false; } // No, so check where the target is now islandTestLocation = plugin.getPlayers().getTeamIslandLocation(owner.getUniqueId()); } else { islandTestLocation = plugin.getPlayers().getIslandLocation(owner.getUniqueId()); } // Check position of target if (islandTestLocation == null) { return false; } int protectionRange = Settings.islandProtectionRange; if (getIslandAt(islandTestLocation) != null) { Island island = getProtectedIslandAt(islandTestLocation); // Get the protection range for this location if possible if (island != null) { // We are in a protected island area. protectionRange = island.getProtectionSize(); } } return target.getLocation().getX() > islandTestLocation.getX() - protectionRange / 2D && target.getLocation().getX() < islandTestLocation.getX() + protectionRange / 2D && target.getLocation().getZ() > islandTestLocation.getZ() - protectionRange / 2D && target.getLocation().getZ() < islandTestLocation.getZ() + protectionRange / 2D; } return false; } /** * Transfers ownership of an island from one player to another * * @param oldOwner old owner UUID * @param newOwner new owner UUID * @return true if successful */ public boolean transferIsland(final UUID oldOwner, final UUID newOwner) { if (plugin.getPlayers().hasIsland(oldOwner)) { Location islandLoc = plugin.getPlayers().getIslandLocation(oldOwner); plugin.getPlayers().setHasIsland(newOwner, true); plugin.getPlayers().setIslandLocation(newOwner, islandLoc); // plugin.getPlayers().setIslandLevel(newOwner, // plugin.getPlayers().getIslandLevel(oldOwner)); plugin.getPlayers().setTeamIslandLocation(newOwner, null); plugin.getPlayers().setHasIsland(oldOwner, false); plugin.getPlayers().setIslandLocation(oldOwner, null); // plugin.getPlayers().setIslandLevel(oldOwner, 0); plugin.getPlayers().setTeamIslandLocation(oldOwner, islandLoc); // Update grid Island island = getIslandAt(islandLoc); if (island != null) { setIslandOwner(island, newOwner); } // Update top ten list // Remove old owner score from top ten list plugin.getTopTen().remove(oldOwner); // Fire event plugin.getServer().getPluginManager().callEvent(new IslandChangeOwnerEvent(island, oldOwner, newOwner)); return true; } return false; } /** * Removes monsters around location l * * @param l location */ public void removeMobs(final Location l) { if (!inWorld(l)) { return; } //plugin.getLogger().info("DEBUG: removing mobs"); // Don't remove mobs if at spawn if (this.isAtSpawn(l)) { //plugin.getLogger().info("DEBUG: at spawn!"); return; } final int px = l.getBlockX(); final int py = l.getBlockY(); final int pz = l.getBlockZ(); for (int x = -1; x <= 1; x++) { for (int z = -1; z <= 1; z++) { final Chunk c = l.getWorld().getChunkAt(new Location(l.getWorld(), px + x * 16, py, pz + z * 16)); if (c.isLoaded()) { for (final Entity e : c.getEntities()) { //plugin.getLogger().info("DEBUG: " + e.getType()); // Don't remove if the entity is an NPC or has a name tag if (e.getCustomName() != null || e.hasMetadata("NPC")) continue; if (e instanceof Monster && !Settings.mobWhiteList.contains(e.getType())) { e.remove(); } } } } } } /** * This removes players from an island overworld and nether - used when reseting or deleting an island * Mobs are killed when the chunks are refreshed. * @param island to remove players from * @param uuid - uuid to ignore */ public void removePlayersFromIsland(final Island island, UUID uuid) { // Teleport players away for (Player player : plugin.getServer().getOnlinePlayers()) { if (island.inIslandSpace(player.getLocation())) { //plugin.getLogger().info("DEBUG: in island space"); // Teleport island players to their island home if (!player.getUniqueId().equals(uuid) && (plugin.getPlayers().hasIsland(player.getUniqueId()) || plugin.getPlayers().inTeam(player.getUniqueId()))) { //plugin.getLogger().info("DEBUG: home teleport"); homeTeleport(player); } else { //plugin.getLogger().info("DEBUG: move player to spawn"); // Move player to spawn Island spawn = getSpawn(); if (spawn != null) { // go to island spawn player.teleport(ASkyBlock.getIslandWorld().getSpawnLocation()); //plugin.getLogger().warning("During island deletion player " + player.getName() + " sent to spawn."); } else { if (!player.performCommand(Settings.SPAWNCOMMAND)) { plugin.getLogger().warning( "During island deletion player " + player.getName() + " could not be sent to spawn so was dropped, sorry."); } } } } } } /** * @return a list of unowned islands */ public HashMap<String, Island> getUnownedIslands() { HashMap<String, Island> result = new HashMap<String,Island>(); for (Entry<Integer, TreeMap<Integer, Island>> x : islandGrid.entrySet()) { for (Island island : x.getValue().values()) { //plugin.getLogger().info("DEBUG: checking island at " + island.getCenter()); if (island.getOwner() == null && !island.isSpawn() && !island.isPurgeProtected()) { Location center = island.getCenter(); String serialized = island.getCenter().getWorld().getName() + ":" + center.getBlockX() + ":" + center.getBlockY() + ":" + center.getBlockZ(); result.put(serialized,island); } } } return result; } /** * Set the spawn point for the island world * @param location island location */ public void setSpawnPoint(Location location) { ASkyBlock.getIslandWorld().setSpawnLocation(location.getBlockX(), location.getBlockY(), location.getBlockZ()); //plugin.getLogger().info("DEBUG: setting spawn point to " + location); spawn.setSpawnPoint(location); } /** * @return the spawnPoint or null if spawn does not exist */ public Location getSpawnPoint() { //plugin.getLogger().info("DEBUG: getting spawn point : " + spawn.getSpawnPoint()); if (spawn == null) return null; return spawn.getSpawnPoint(); } /** * @return how many islands are in the grid */ public int getIslandCount() { return ownershipMap.size(); } /** * Get the ownership map of islands * @return Hashmap of owned islands with owner UUID as a key * */ public HashMap<UUID, Island> getOwnedIslands() { return ownershipMap; } /** * Get name of the island owned by owner * @param owner island owner UUID * @return Returns the name of owner's island, or the owner's name if there is none. */ public String getIslandName(UUID owner) { if (owner == null) { return ""; } return ChatColor.translateAlternateColorCodes('&', islandNames.getString(owner.toString(), plugin.getPlayers().getName(owner))) + ChatColor.RESET; } /** * Set the island name * @param owner island owner UUID * @param name name to set */ public void setIslandName(UUID owner, String name) { islandNames.set(owner.toString(), name); Util.saveYamlFile(islandNames, ISLANDNAMES_FILENAME, true); } }