diff --git a/src/main/java/us/tastybento/bskyblock/BSkyBlock.java b/src/main/java/us/tastybento/bskyblock/BSkyBlock.java index 51a85c5d5..a79b5d1f1 100755 --- a/src/main/java/us/tastybento/bskyblock/BSkyBlock.java +++ b/src/main/java/us/tastybento/bskyblock/BSkyBlock.java @@ -18,6 +18,7 @@ import us.tastybento.bskyblock.config.BSBLocale; import us.tastybento.bskyblock.config.PluginConfig; import us.tastybento.bskyblock.config.Settings; import us.tastybento.bskyblock.database.BSBDatabase; +import us.tastybento.bskyblock.database.BSBDatabase.DatabaseType; import us.tastybento.bskyblock.database.managers.IslandsManager; import us.tastybento.bskyblock.database.managers.OfflineHistoryMessages; import us.tastybento.bskyblock.database.managers.PlayersManager; @@ -64,7 +65,7 @@ public class BSkyBlock extends JavaPlugin{ Settings.dbName = "ASkyBlock"; Settings.dbUsername = "username"; Settings.dbPassword = "password"; - */ + */ playersManager = new PlayersManager(this); islandsManager = new IslandsManager(this); // Only load metrics if set to true in config diff --git a/src/main/java/us/tastybento/bskyblock/commands/AdminCommand.java b/src/main/java/us/tastybento/bskyblock/commands/AdminCommand.java index 46ca3038c..baf8054dc 100755 --- a/src/main/java/us/tastybento/bskyblock/commands/AdminCommand.java +++ b/src/main/java/us/tastybento/bskyblock/commands/AdminCommand.java @@ -1,31 +1,60 @@ package us.tastybento.bskyblock.commands; +import java.util.List; + import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import us.tastybento.bskyblock.BSkyBlock; +import us.tastybento.bskyblock.util.VaultHelper; public class AdminCommand extends BSBCommand{ + + BSkyBlock plugin; public AdminCommand(BSkyBlock plugin) { super(plugin, true); - // TODO Auto-generated constructor stub } @Override public void setup() { - // TODO Auto-generated method stub + /* /asadmin delete - delete name's island */ + registerArgument(new String[] {"delete"}, new CommandArgumentHandler() { + + @Override + public boolean canExecute(CommandSender sender, String label, String[] args) { + // TODO Auto-generated method stub + return true; + } + + @Override + public void onExecute(CommandSender sender, String label, String[] args) { + + } + + @Override + public List onTabComplete(CommandSender sender, String label, String[] args) { + // TODO Auto-generated method stub + return null; + } + + @Override + public String[] getHelp(CommandSender sender, String label){ + return new String[] {null, plugin.getLocale(sender).get("help.admin.delete")}; + } + }); } @Override public boolean canExecute(CommandSender sender, String label) { // TODO Auto-generated method stub - return false; + return true; } @Override public void onExecuteDefault(CommandSender sender, String label, String[] args) { - // TODO Auto-generated method stub + } diff --git a/src/main/java/us/tastybento/bskyblock/commands/IslandCommand.java b/src/main/java/us/tastybento/bskyblock/commands/IslandCommand.java index 8d58c268c..26b7c7add 100755 --- a/src/main/java/us/tastybento/bskyblock/commands/IslandCommand.java +++ b/src/main/java/us/tastybento/bskyblock/commands/IslandCommand.java @@ -255,11 +255,11 @@ public class IslandCommand extends BSBCommand{ } Player player = (Player)sender; if (plugin.getIslands().hasIsland(player.getUniqueId())) { - // Delete island - new DeleteIslandBlocks(plugin, plugin.getIslands().getIsland(player.getUniqueId())); + plugin.getIslands().deletePlayerIsland(player.getUniqueId(), true); // Create new island Schematic schematic = plugin.getSchematics().getSchematic("default"); - plugin.getIslands().newIsland(player, schematic); + plugin.getIslands().newIsland(player, schematic); + } else { Util.sendMessage(player, plugin.getLocale(player.getUniqueId()).get("error.noIsland")); } diff --git a/src/main/java/us/tastybento/bskyblock/database/flatfile/FlatFileDatabaseHandler.java b/src/main/java/us/tastybento/bskyblock/database/flatfile/FlatFileDatabaseHandler.java index b5c511604..ff904bedd 100644 --- a/src/main/java/us/tastybento/bskyblock/database/flatfile/FlatFileDatabaseHandler.java +++ b/src/main/java/us/tastybento/bskyblock/database/flatfile/FlatFileDatabaseHandler.java @@ -49,6 +49,11 @@ public class FlatFileDatabaseHandler extends AbstractDatabaseHandler { protected String createInsertQuery() { return ""; // not used } + @Override + protected String createDeleteQuery() { + // TODO Auto-generated method stub + return null; + } /** * Creates a filled with values from the corresponding * database file @@ -220,7 +225,7 @@ public class FlatFileDatabaseHandler extends AbstractDatabaseHandler { // Check if this field is the mandatory UniqueId field. This is used to identify this instantiation of the class if (method.getName().equals("getUniqueId")) { // If the object does not have a unique name assigned to it already, one is created at random - plugin.getLogger().info("DEBUG: uniqueId = " + value); + //plugin.getLogger().info("DEBUG: uniqueId = " + value); String id = (String)value; if (id.isEmpty()) { id = databaseConnecter.getUniqueId(type.getSimpleName()); @@ -230,7 +235,7 @@ public class FlatFileDatabaseHandler extends AbstractDatabaseHandler { // Save the name for when the file is saved filename = id; } - // UUID's need special serialization + // Collections need special serialization if (propertyDescriptor.getPropertyType().equals(HashMap.class) || propertyDescriptor.getPropertyType().equals(Map.class)) { // Maps need to have keys serialized //plugin.getLogger().info("DEBUG: Map for " + field.getName()); @@ -296,6 +301,10 @@ public class FlatFileDatabaseHandler extends AbstractDatabaseHandler { // If the value is null as a string, return null return null; } + // Bukkit may have deserialized the object already + if (clazz.equals(value.getClass())) { + return value; + } // Types that need to be deserialized if (clazz.equals(UUID.class)) { value = UUID.fromString((String)value); @@ -325,4 +334,21 @@ public class FlatFileDatabaseHandler extends AbstractDatabaseHandler { return value; } + @Override + protected void deleteObject(T instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException { + // The file name of the Yaml file. + PropertyDescriptor propertyDescriptor = new PropertyDescriptor("uniqueId", type); + Method method = propertyDescriptor.getReadMethod(); + String fileName = (String) method.invoke(instance); + if (!fileName.endsWith(".yml")) { + fileName = fileName + ".yml"; + } + File dataFolder = new File(plugin.getDataFolder(), DATABASE_FOLDER_NAME); + File tableFolder = new File(dataFolder, type.getSimpleName()); + if (tableFolder.exists()) { + File file = new File(tableFolder, fileName); + file.delete(); + } + } + } diff --git a/src/main/java/us/tastybento/bskyblock/database/managers/AbstractDatabaseHandler.java b/src/main/java/us/tastybento/bskyblock/database/managers/AbstractDatabaseHandler.java index c95809429..f860af428 100644 --- a/src/main/java/us/tastybento/bskyblock/database/managers/AbstractDatabaseHandler.java +++ b/src/main/java/us/tastybento/bskyblock/database/managers/AbstractDatabaseHandler.java @@ -8,6 +8,7 @@ import java.util.List; import us.tastybento.bskyblock.BSkyBlock; import us.tastybento.bskyblock.database.DatabaseConnecter; +import us.tastybento.bskyblock.database.objects.Island; /** * An abstract class that handles insert/select-operations into/from a database @@ -36,6 +37,7 @@ public abstract class AbstractDatabaseHandler { /** The SQL-select- and insert query */ protected final String selectQuery; protected final String insertQuery; + protected final String deleteQuery; protected BSkyBlock plugin; @@ -57,15 +59,17 @@ public abstract class AbstractDatabaseHandler { this.type = type; this.selectQuery = createSelectQuery(); this.insertQuery = createInsertQuery(); + this.deleteQuery = createDeleteQuery(); } /** - * Create the SQL-String to insert into / select from the database + * Create the SQL-String to insert into / select / delete from the database * Not used in the flat file database * @return the SQL-String */ protected abstract String createSelectQuery(); protected abstract String createInsertQuery(); + protected abstract String createDeleteQuery(); /** * @@ -142,4 +146,17 @@ public abstract class AbstractDatabaseHandler { */ protected abstract void saveObject(T instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException, SQLException, SecurityException, InstantiationException, NoSuchMethodException; + /** + * Deletes the object with the unique id from the database + * @param instance + * @throws InvocationTargetException + * @throws IllegalArgumentException + * @throws IllegalAccessException + * @throws IntrospectionException + * @throws SQLException + * @throws SecurityException + * @throws NoSuchMethodException + */ + protected abstract void deleteObject(T instance) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, IntrospectionException, SQLException, NoSuchMethodException, SecurityException; + } diff --git a/src/main/java/us/tastybento/bskyblock/database/managers/IslandsManager.java b/src/main/java/us/tastybento/bskyblock/database/managers/IslandsManager.java index b6de81e58..fd842b2a3 100644 --- a/src/main/java/us/tastybento/bskyblock/database/managers/IslandsManager.java +++ b/src/main/java/us/tastybento/bskyblock/database/managers/IslandsManager.java @@ -1,5 +1,7 @@ package us.tastybento.bskyblock.database.managers; +import java.beans.IntrospectionException; +import java.lang.reflect.InvocationTargetException; import java.util.HashSet; import java.util.Map.Entry; import java.util.Set; @@ -30,6 +32,7 @@ import us.tastybento.bskyblock.database.objects.Island; import us.tastybento.bskyblock.generators.IslandWorld; import us.tastybento.bskyblock.schematics.Schematic; import us.tastybento.bskyblock.schematics.Schematic.PasteReason; +import us.tastybento.bskyblock.util.DeleteIslandBlocks; import us.tastybento.bskyblock.util.SafeSpotTeleport; import us.tastybento.bskyblock.util.Util; @@ -175,6 +178,55 @@ public class IslandsManager { } } + /** + * Delete island owned by UniqueId + * @param uniqueId + */ + public void deleteIsland(UUID uniqueId){ + if (islandsByUUID.containsKey(uniqueId)) { + Island island = islandsByLocation.get(uniqueId); + islandsByUUID.remove(uniqueId); + islandsByLocation.remove(island.getCenter()); + } + } + + /** + * Delete Island + * Called when an island is restarted or reset + * + * @param player + * - player name String + * @param removeBlocks + * - true to remove the island blocks + */ + public void deletePlayerIsland(final UUID player, boolean removeBlocks) { + // Removes the island + //getLogger().info("DEBUG: deleting player island"); + //CoopPlay.getInstance().clearAllIslandCoops(player); + //getWarpSignsListener().removeWarp(player); + Island island = getIsland(player); + if (island != null) { + if (removeBlocks) { + removePlayersFromIsland(island, player); + new DeleteIslandBlocks(plugin, island); + try { + handler.deleteObject(island); + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } else { + island.setLocked(false); + island.setOwner(null); + } + //getServer().getPluginManager().callEvent(new IslandDeleteEvent(player, island.getCenter())); + } else { + plugin.getLogger().severe("Could not delete player: " + player.toString() + " island!"); + //plugin.getServer().getPluginManager().callEvent(new IslandDeleteEvent(player, null)); + } + //players.zeroPlayerData(player); + } + public Island getSpawn(){ return spawn; } @@ -423,7 +475,7 @@ public class IslandsManager { return true; } - + /** * Determines a safe teleport spot on player's island or the team island * they belong to. @@ -601,7 +653,7 @@ public class IslandsManager { // Nothing worked return null; } - + /** * 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 @@ -682,7 +734,7 @@ public class IslandsManager { //Bukkit.getLogger().info("DEBUG: safe!"); return true; } - + /** * Makes an island using schematic. No permission checks are made. They have to be decided * before this method is called. @@ -690,15 +742,16 @@ public class IslandsManager { * @param schematic */ public void newIsland(final Player player, final Schematic schematic) { + plugin.getLogger().info("DEBUG: new island"); //long time = System.nanoTime(); final UUID playerUUID = player.getUniqueId(); boolean firstTime = false; if (!plugin.getPlayers().hasIsland(playerUUID)) { firstTime = true; } - //plugin.getLogger().info("DEBUG: finding island location"); + plugin.getLogger().info("DEBUG: finding island location"); Location next = getNextIsland(player.getUniqueId()); - //plugin.getLogger().info("DEBUG: found " + next); + plugin.getLogger().info("DEBUG: found " + next); // Clear any old home locations (they should be clear, but just in case) plugin.getPlayers().clearHomeLocations(playerUUID); @@ -829,17 +882,20 @@ public class IslandsManager { * @return Location of island spot */ private Location getNextIsland(UUID playerUUID) { + plugin.getLogger().info("DEBUG: last = " + last); // Find the next free spot if (last == null) { last = new Location(IslandWorld.getIslandWorld(), Settings.islandXOffset + Settings.islandStartX, Settings.islandHeight, Settings.islandZOffset + Settings.islandStartZ); } Location next = last.clone(); - - while (plugin.getIslands().isIsland(next)) { + plugin.getLogger().info("DEBUG: last 2 = " + last); + do { + plugin.getLogger().info("DEBUG: getting next loc"); next = nextGridLocation(next); - } + } while (isIsland(next)); // Make the last next, last last = next.clone(); + plugin.getLogger().info("DEBUG: last 3 = " + last); return next; } @@ -851,7 +907,7 @@ public class IslandsManager { * @return Location of next free island */ private Location nextGridLocation(final Location lastIsland) { - // plugin.getLogger().info("DEBUG nextIslandLocation"); + plugin.getLogger().info("DEBUG: nextIslandLocation - island distance = " + Settings.islandDistance); final int x = lastIsland.getBlockX(); final int z = lastIsland.getBlockZ(); final Location nextPos = lastIsland; @@ -878,5 +934,39 @@ public class IslandsManager { nextPos.setZ(nextPos.getZ() - Settings.islandDistance); return nextPos; } + + /** + * 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 + */ + public void removePlayersFromIsland(final Island island, UUID uuid) { + // Teleport players away + for (Player player : plugin.getServer().getOnlinePlayers()) { + if (island.inIslandSpace(player.getLocation().getBlockX(), player.getLocation().getBlockZ())) { + //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(IslandWorld.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."); + } + } + } + } + } + } } diff --git a/src/main/java/us/tastybento/bskyblock/database/managers/PlayersManager.java b/src/main/java/us/tastybento/bskyblock/database/managers/PlayersManager.java index 8ee0b7cfe..b97d83a29 100644 --- a/src/main/java/us/tastybento/bskyblock/database/managers/PlayersManager.java +++ b/src/main/java/us/tastybento/bskyblock/database/managers/PlayersManager.java @@ -108,14 +108,14 @@ public class PlayersManager{ public Players addPlayer(final UUID playerUUID) { if (playerUUID == null) return null; - plugin.getLogger().info("DEBUG: added player " + playerUUID); + //plugin.getLogger().info("DEBUG: added player " + playerUUID); if (!playerCache.containsKey(playerUUID)) { plugin.getLogger().info("DEBUG: new player"); final Players player = new Players(playerUUID); playerCache.put(playerUUID, player); return player; } else { - plugin.getLogger().info("DEBUG: returning cache"); + //plugin.getLogger().info("DEBUG: known player"); return playerCache.get(playerUUID); } } diff --git a/src/main/java/us/tastybento/bskyblock/database/mysql/MySQLDatabaseHandler.java b/src/main/java/us/tastybento/bskyblock/database/mysql/MySQLDatabaseHandler.java index bd8ce3659..d5034e3e9 100644 --- a/src/main/java/us/tastybento/bskyblock/database/mysql/MySQLDatabaseHandler.java +++ b/src/main/java/us/tastybento/bskyblock/database/mysql/MySQLDatabaseHandler.java @@ -16,7 +16,6 @@ import java.sql.Statement; import java.sql.Time; import java.sql.Timestamp; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.Date; import java.util.HashMap; @@ -293,6 +292,10 @@ public class MySQLDatabaseHandler extends AbstractDatabaseHandler { return sb.toString(); } + protected String createDeleteQuery() { + return "DELETE FROM [table_name] WHERE uniqueId = ?"; + } + /** * Inserts a into the corresponding database-table * @@ -721,4 +724,63 @@ public class MySQLDatabaseHandler extends AbstractDatabaseHandler { return value; } + /* (non-Javadoc) + * @see us.tastybento.bskyblock.database.managers.AbstractDatabaseHandler#deleteObject(java.lang.Object) + */ + @Override + protected void deleteObject(T instance) + throws IllegalAccessException, IllegalArgumentException, + InvocationTargetException, IntrospectionException, SQLException, NoSuchMethodException, SecurityException { + // Delete this object from all tables + Connection connection = null; + PreparedStatement preparedStatement = null; + + try { + // Try to connect to the database + connection = databaseConnecter.createConnection(); + // Get the uniqueId. As each class extends DataObject, it must have this method in it. + Method getUniqueId = type.getMethod("getUniqueId"); + String uniqueId = (String) getUniqueId.invoke(instance); + //plugin.getLogger().info("DEBUG: Unique Id = " + uniqueId); + if (uniqueId.isEmpty()) { + throw new SQLException("uniqueId is blank"); + } + // Delete from the main table + // First substitution is the table name + // deleteQuery is created in super from the createInsertQuery() method + preparedStatement = connection.prepareStatement(deleteQuery.replace("[table_name]", "`" + type.getCanonicalName() + "`")); + // Second is the unique ID + preparedStatement.setString(1, uniqueId); + preparedStatement.addBatch(); + plugin.getLogger().info("DEBUG: DELETE Query " + preparedStatement.toString()); + preparedStatement.executeBatch(); + // Delete from any sub tables created from the object + // Run through the fields in the class using introspection + for (Field field : type.getDeclaredFields()) { + // Get the field's property descriptor + PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), type); + // Delete Collection tables + if (propertyDescriptor.getPropertyType().equals(Set.class) || + propertyDescriptor.getPropertyType().equals(Map.class) || + propertyDescriptor.getPropertyType().equals(HashMap.class) || + propertyDescriptor.getPropertyType().equals(ArrayList.class)) { + // First substitution is the table name + preparedStatement = connection.prepareStatement(deleteQuery.replace("[table_name]", "`" + type.getCanonicalName() + "." + field.getName() + "`")); + // Second is the unique ID + preparedStatement.setString(1, uniqueId); + preparedStatement.addBatch(); + // Execute + plugin.getLogger().info("DEBUG: " + preparedStatement.toString()); + preparedStatement.executeBatch(); + } + } + } finally { + // Close properly + MySQLDatabaseResourceCloser.close(preparedStatement); + } + + } + + + } diff --git a/src/main/java/us/tastybento/bskyblock/util/DeleteIslandBlocks.java b/src/main/java/us/tastybento/bskyblock/util/DeleteIslandBlocks.java index d78af771e..794a4b93b 100644 --- a/src/main/java/us/tastybento/bskyblock/util/DeleteIslandBlocks.java +++ b/src/main/java/us/tastybento/bskyblock/util/DeleteIslandBlocks.java @@ -47,12 +47,21 @@ public class DeleteIslandBlocks { //private HashMap blocksToClear = new HashMap(); private NMSAbstraction nms = null; + /** + * Deletes the island + * @param plugin + * @param island + */ public DeleteIslandBlocks(final BSkyBlock plugin, final Island island) { + plugin.getLogger().info("DEBUG: deleting the island"); final World world = island.getCenter().getWorld(); if (world == null) return; // Determine if blocks need to be cleaned up or not boolean cleanUpBlocks = false; + plugin.getLogger().info("DEBUG: island protection = " + island.getProtectionRange()); + // DEBUG + island.setProtectionRange(Settings.islandDistance); if (Settings.islandDistance - island.getProtectionRange() < 16) { cleanUpBlocks = true; } @@ -61,8 +70,7 @@ public class DeleteIslandBlocks { final int minz = island.getMinProtectedZ(); final int maxx = island.getMinProtectedX() + island.getProtectionRange(); final int maxz = island.getMinProtectedZ() + island.getProtectionRange(); - // plugin.getLogger().info("DEBUG: protection limits are: " + minx + - // ", " + minz + " to " + maxx + ", " + maxz ); + plugin.getLogger().info("DEBUG: protection limits are: " + minx + ", " + minz + " to " + maxx + ", " + maxz ); int islandSpacing = Settings.islandDistance - island.getProtectionRange(); int minxX = (island.getCenter().getBlockX() - range - islandSpacing); int minzZ = (island.getCenter().getBlockZ() - range - islandSpacing);