diff --git a/src/de/diddiz/LogBlock/CommandsHandler.java b/src/de/diddiz/LogBlock/CommandsHandler.java index 542bcf4..cb521e3 100644 --- a/src/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/de/diddiz/LogBlock/CommandsHandler.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock; +import static de.diddiz.util.BukkitUtils.giveTool; import java.io.Closeable; import java.io.File; import java.io.FileWriter; @@ -27,7 +28,6 @@ import de.diddiz.LogBlock.QueryParams.SummarizationMode; import de.diddiz.LogBlock.WorldEditor.WorldEditorException; import de.diddiz.LogBlockQuestioner.LogBlockQuestioner; import de.diddiz.LogBlockQuestioner.QuestionerException; -import de.diddiz.util.BukkitUtils; public class CommandsHandler implements CommandExecutor { @@ -109,7 +109,7 @@ public class CommandsHandler implements CommandExecutor final Player player = (Player)sender; if (args.length == 1) { if (logblock.hasPermission(player, "logblock.tool")) - BukkitUtils.giveTool(player, config.toolID); + giveTool(player, config.toolID); else sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); } else if (args[1].equalsIgnoreCase("enable") || args[1].equalsIgnoreCase("on")) { @@ -135,7 +135,7 @@ public class CommandsHandler implements CommandExecutor final Player player = (Player)sender; if (args.length == 1) { if (logblock.hasPermission(player, "logblock.toolblock")) - BukkitUtils.giveTool(player, config.toolblockID); + giveTool(player, config.toolblockID); else player.sendMessage(ChatColor.RED + "You aren't allowed to do this."); } else if (args[1].equalsIgnoreCase("enable") || args[1].equalsIgnoreCase("on")) { @@ -430,12 +430,24 @@ public class CommandsHandler implements CommandExecutor @Override public void run() { try { - rs = state.executeQuery(params.getQuery()); + final int queue = logblock.getConsumer().getQueueSize(); + if (queue > 50 && (!config.askSavequeueBeforeRollback || questioner != null && sender instanceof Player && questioner.askQuestion((Player)sender, "There are " + queue + " block in queue. Do yu want to process the queue before rollback?", "yes", "no").equals("yes"))) + try { + new CommandSaveQueue(sender, null); + } catch (final Exception ex) { + sender.sendMessage(ChatColor.RED + ex.getMessage()); + } sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); + rs = state.executeQuery(params.getQuery()); final WorldEditor editor = new WorldEditor(logblock, params.world); while (rs.next()) editor.queueBlockChange(rs.getInt("type"), rs.getInt("replaced"), rs.getByte("data"), rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getString("signtext"), rs.getShort("itemtype"), rs.getShort("itemamount"), rs.getByte("itemdata")); final int changes = editor.getSize(); + if (changes == 0) { + sender.sendMessage(ChatColor.RED.toString() + changes + " blocks found."); + sender.sendMessage(ChatColor.RED + "Rollback aborted"); + return; + } sender.sendMessage(ChatColor.GREEN.toString() + changes + " blocks found."); if (config.askRollbacks && questioner != null && sender instanceof Player && !questioner.askQuestion((Player)sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { sender.sendMessage(ChatColor.RED + "Rollback aborted"); @@ -445,6 +457,8 @@ public class CommandsHandler implements CommandExecutor sender.sendMessage(ChatColor.GREEN + "Rollback finished successfully"); sender.sendMessage(ChatColor.GREEN + "Undid " + editor.getSuccesses() + " of " + changes + " changes (" + editor.getErrors() + " errors, " + editor.getBlacklistCollisions() + " blacklist collisions)"); sender.sendMessage(ChatColor.GREEN + "Took: " + editor.getElapsedTime() + "ms"); + if (logblock.hasPermission(sender, "logblock.clearlog")) + sender.sendMessage(ChatColor.LIGHT_PURPLE + "Delete the log with '/lb clearlog last'"); } catch (final SQLException ex) { sender.sendMessage(ChatColor.RED + "SQL exception"); log.log(Level.SEVERE, "[LogBlock Rollback] SQL exception", ex); @@ -475,6 +489,11 @@ public class CommandsHandler implements CommandExecutor while (rs.next()) editor.queueBlockChange(rs.getInt("replaced"), rs.getInt("type"), rs.getByte("data"), rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getString("signtext"), rs.getShort("itemtype"), (short)(rs.getShort("itemamount") * 1), rs.getByte("itemdata")); final int changes = editor.getSize(); + if (changes == 0) { + sender.sendMessage(ChatColor.RED.toString() + changes + " blocks found."); + sender.sendMessage(ChatColor.RED + "Redo aborted"); + return; + } sender.sendMessage(ChatColor.GREEN.toString() + changes + " blocks found."); if (config.askRedos && questioner != null && sender instanceof Player && !questioner.askQuestion((Player)sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) { sender.sendMessage(ChatColor.RED + "Redo aborted"); @@ -512,7 +531,12 @@ public class CommandsHandler implements CommandExecutor final SimpleDateFormat formatter = new SimpleDateFormat("yyMMddHHmmss"); int deleted; final String table = params.getTable(); - rs = state.executeQuery("SELECT count(*) FROM `" + table + "` " + params.getWhere()); + final String join; + if (params.players.size() > 0) + join = "INNER JOIN `lb-players` USING (playerid) "; + else + join = ""; + rs = state.executeQuery("SELECT count(*) FROM `" + table + "` " + join + params.getWhere()); rs.next(); if ((deleted = rs.getInt(1)) > 0) { if (config.askClearLogs && sender instanceof Player && questioner != null) { @@ -525,13 +549,13 @@ public class CommandsHandler implements CommandExecutor } if (config.dumpDeletedLog) try { - state.execute("SELECT * FROM `" + table + "` " + params.getWhere() + "INTO OUTFILE '" + new File(dumpFolder, formatter.format(System.currentTimeMillis()) + " " + table + " " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); + state.execute("SELECT * FROM `" + table + "` " + join + params.getWhere() + "INTO OUTFILE '" + new File(dumpFolder, formatter.format(System.currentTimeMillis()) + " " + table + " " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'"); } catch (final SQLException ex) { sender.sendMessage(ChatColor.RED + "Error while dumping log. Make sure your MySQL user has access to the LogBlock folder, or disable clearlog.dumpDeletedLog"); log.log(Level.SEVERE, "[LogBlock ClearLog] Exception while dumping", ex); return; } - state.execute("DELETE FROM `" + table + "` " + params.getWhere()); + state.execute("DELETE `" + table + "` FROM `" + table + "` " + join + params.getWhere()); sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + ". Deleted " + deleted + " entries."); } rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-sign` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL"); @@ -562,75 +586,10 @@ public class CommandsHandler implements CommandExecutor } } - private List ArgsToList(String[] arr, int offset) { + private static List ArgsToList(String[] arr, int offset) { final List list = new ArrayList(Arrays.asList(arr)); for (int i = 0; i < offset; i++) list.remove(0); return list; } - - private class HistoryFormatter - { - private final SimpleDateFormat formatter = new SimpleDateFormat("MM-dd HH:mm:ss"); - private final SummarizationMode sum; - - HistoryFormatter(SummarizationMode sum) { - this.sum = sum; - } - - String format(ResultSet rs) { - try { - if (sum == SummarizationMode.NONE) { - final StringBuilder msg = new StringBuilder(formatter.format(rs.getTimestamp("date")) + " " + rs.getString("playername") + " "); - final int type = rs.getInt("type"); - final int replaced = rs.getInt("replaced"); - final String signtext; - if ((type == 63 || type == 68 || replaced == 63 || replaced == 68) && (signtext = rs.getString("signtext")) != null) { - final String action; - if (type == 0) - action = "destroyed "; - else - action = "created "; - if (!signtext.contains("\0")) - msg.append(action + signtext); - else - msg.append(action + "sign [" + signtext.replace("\0", "] [") + "]"); - } else if (type == replaced) { - if (type == 0) - msg.append("did a unspecified action"); - else if (type == 23 || type == 54 || type == 61) { - final int itemType = rs.getInt("itemtype"); - final int itemAmount = rs.getInt("itemamount"); - if (itemType == 0 || itemAmount == 0) - msg.append("looked inside " + BukkitUtils.getMaterialName(type)); - else if (itemAmount < 0) - msg.append("took " + itemAmount * -1 + "x " + BukkitUtils.getMaterialName(itemType)); - else - msg.append("put in " + itemAmount + "x " + BukkitUtils.getMaterialName(itemType)); - } - } else if (type == 0) - msg.append("destroyed " + BukkitUtils.getMaterialName(replaced)); - else if (replaced == 0) - msg.append("created " + BukkitUtils.getMaterialName(type)); - else - msg.append("replaced " + BukkitUtils.getMaterialName(replaced) + " with " + BukkitUtils.getMaterialName(type)); - return msg.toString(); - } else if (sum == SummarizationMode.TYPES) - return fillWithSpaces(rs.getInt("created")) + fillWithSpaces(rs.getInt("destroyed")) + BukkitUtils.getMaterialName(rs.getInt("type")); - else - return fillWithSpaces(rs.getInt("created")) + fillWithSpaces(rs.getInt("destroyed")) + rs.getString("playername"); - } catch (final SQLException ex) { - log.log(Level.SEVERE, "[LogBlock HistoryFormatter] Error", ex); - return null; - } - } - - private String fillWithSpaces(Integer number) { - final StringBuilder filled = new StringBuilder(number.toString()); - final int neededSpaces = (36 - filled.length() * 6) / 4; - for (int i = 0; i < neededSpaces; i++) - filled.append(' '); - return filled.toString(); - } - } } diff --git a/src/de/diddiz/LogBlock/Config.java b/src/de/diddiz/LogBlock/Config.java index 89a0849..ebfa850 100644 --- a/src/de/diddiz/LogBlock/Config.java +++ b/src/de/diddiz/LogBlock/Config.java @@ -1,57 +1,42 @@ package de.diddiz.LogBlock; +import static de.diddiz.util.Utils.parseTimeSpec; +import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Set; +import java.util.zip.DataFormatException; import org.bukkit.Material; import org.bukkit.command.ConsoleCommandSender; import org.bukkit.util.config.Configuration; -import de.diddiz.util.Utils; public class Config { public final HashMap tables; - public final String url; - public final String user; - public final String password; - public final int delayBetweenRuns; - public final int forceToProcessAtLeast; - public final int timePerRun; + public final String url, user, password; + public final int delayBetweenRuns, forceToProcessAtLeast, timePerRun; public final boolean useBukkitScheduler; public final int keepLogDays; public final boolean dumpDeletedLog; - public final boolean logBlockCreations; - public final boolean logBlockDestroyings; - public final boolean logSignTexts; - public final boolean logExplosions; + public final boolean logBlockCreations, logBlockDestroyings, logSignTexts, logExplosions, logFire, logLeavesDecay, logLavaFlow, logChestAccess, logKills; public final boolean logCreeperExplosionsAsPlayerWhoTriggeredThese; - public final boolean logFire; - public final boolean logLeavesDecay; - public final boolean logLavaFlow; - public final boolean logChestAccess; - public final boolean logKills; public final LogKillsLevel logKillsLevel; public final Set dontRollback; public final Set replaceAnyway; - public final QueryParams toolQuery; - public final QueryParams toolBlockQuery; - public final int defaultDist; - public final int defaultTime; - public final int toolID; - public final int toolblockID; - public final boolean askRollbacks; - public final boolean askRedos; - public final boolean askClearLogs; + public final QueryParams toolQuery, toolBlockQuery; + public final int defaultDist, defaultTime; + public final int toolID, toolblockID; + public final boolean askRollbacks, askRedos, askClearLogs, askSavequeueBeforeRollback; public final Set hiddenPlayers; public static enum LogKillsLevel { PLAYERS, MONSTERS, ANIMALS } - Config(LogBlock logblock) throws Exception { + Config(LogBlock logblock) throws DataFormatException, IOException { final Configuration config = logblock.getConfiguration(); config.load(); final List keys = config.getKeys(null); @@ -59,9 +44,9 @@ public class Config if (!keys.contains("version")) config.setProperty("version", logblock.getDescription().getVersion()); if (!keys.contains("loggedWorlds")) - config.setProperty("loggedWorlds", Arrays.asList(new String[]{"world", "nether"})); + config.setProperty("loggedWorlds", Arrays.asList(new String[]{"world", "world_nether"})); if (!keys.contains("tables")) - config.setProperty("tables", Arrays.asList(new String[]{"lb-main", "lb-hell"})); + config.setProperty("tables", Arrays.asList(new String[]{"lb-main", "lb-nether"})); subkeys = config.getKeys("mysql"); if (subkeys == null) subkeys = new ArrayList(); @@ -90,7 +75,7 @@ public class Config if (subkeys == null) subkeys = new ArrayList(); if (!subkeys.contains("dumpDeletedLog")) - config.setProperty("clearlog.dumpDeletedLog", true); + config.setProperty("clearlog.dumpDeletedLog", false); if (!subkeys.contains("keepLogDays")) config.setProperty("clearlog.keepLogDays", -1); subkeys = config.getKeys("logging"); @@ -119,7 +104,7 @@ public class Config if (!subkeys.contains("logKillsLevel")) config.setProperty("logging.logKillsLevel", "PLAYERS"); if (!subkeys.contains("hiddenPlayers")) - config.setProperty("logging.hiddenPlayers", Arrays.asList(new String[]{"Nessie", "Bigfoot", "Chewbacca"})); + config.setProperty("logging.hiddenPlayers", new ArrayList()); subkeys = config.getKeys("rollback"); if (subkeys == null) subkeys = new ArrayList(); @@ -151,8 +136,10 @@ public class Config config.setProperty("questioner.askRedos", true); if (!subkeys.contains("askClearLogs")) config.setProperty("questioner.askClearLogs", true); + if (!subkeys.contains("askSavequeueBeforeRollback")) + config.setProperty("questioner.askSavequeueBeforeRollback", true); if (!config.save()) - throw new Exception("Error while writing to config.yml"); + throw new IOException("Error while writing to config.yml"); url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getString("mysql.port") + "/" + config.getString("mysql.database"); user = config.getString("mysql.user"); password = config.getString("mysql.password"); @@ -162,8 +149,8 @@ public class Config useBukkitScheduler = config.getBoolean("consumer.useBukkitScheduler", true); keepLogDays = config.getInt("clearlog.keepLogDays", -1); if (keepLogDays * 86400000L > System.currentTimeMillis()) - throw new Exception("Too large timespan for keepLogDays. Must be shorter than " + (int)(System.currentTimeMillis() / 86400000L) + " days."); - dumpDeletedLog = config.getBoolean("clearlog.dumpDeletedLog", true); + throw new DataFormatException("Too large timespan for keepLogDays. Must be shorter than " + (int)(System.currentTimeMillis() / 86400000L) + " days."); + dumpDeletedLog = config.getBoolean("clearlog.dumpDeletedLog", false); logBlockCreations = config.getBoolean("logging.logBlockCreations", true); logBlockDestroyings = config.getBoolean("logging.logBlockDestroyings", true); logSignTexts = config.getBoolean("logging.logSignTexts", false); @@ -177,7 +164,7 @@ public class Config try { logKillsLevel = LogKillsLevel.valueOf(config.getString("logging.logKillsLevel")); } catch (final IllegalArgumentException ex) { - throw new Exception("lookup.toolblockID doesn't appear to be a valid log level. Allowed are 'PLAYERS', 'MONSTERS' and 'ANIMALS'"); + throw new DataFormatException("lookup.toolblockID doesn't appear to be a valid log level. Allowed are 'PLAYERS', 'MONSTERS' and 'ANIMALS'"); } hiddenPlayers = new HashSet(); for (final String playerName : config.getStringList("hiddenPlayers", new ArrayList())) @@ -189,31 +176,32 @@ public class Config toolQuery.prepareToolQuery = true; toolQuery.parseArgs(new ConsoleCommandSender(logblock.getServer()), Arrays.asList(config.getString("lookup.toolQuery").split(" "))); } catch (final IllegalArgumentException ex) { - throw new Exception("Error at lookup.toolQuery: " + ex.getMessage()); + throw new DataFormatException("Error at lookup.toolQuery: " + ex.getMessage()); } try { toolBlockQuery = new QueryParams(logblock); toolBlockQuery.prepareToolQuery = true; toolBlockQuery.parseArgs(new ConsoleCommandSender(logblock.getServer()), Arrays.asList(config.getString("lookup.toolBlockQuery").split(" "))); } catch (final IllegalArgumentException ex) { - throw new Exception("Error at lookup.toolBlockQuery: " + ex.getMessage()); + throw new DataFormatException("Error at lookup.toolBlockQuery: " + ex.getMessage()); } defaultDist = config.getInt("lookup.defaultDist", 20); - defaultTime = Utils.parseTimeSpec(config.getString("lookup.defaultTime").split(" ")); + defaultTime = parseTimeSpec(config.getString("lookup.defaultTime").split(" ")); toolID = config.getInt("lookup.toolID", 270); if (Material.getMaterial(toolID) == null || Material.getMaterial(toolID).isBlock()) - throw new Exception("lookup.toolID doesn't appear to be a valid item id"); + throw new DataFormatException("lookup.toolID doesn't appear to be a valid item id"); toolblockID = config.getInt("lookup.toolblockID", 7); if (Material.getMaterial(toolblockID) == null || !Material.getMaterial(toolblockID).isBlock() || toolblockID == 0) - throw new Exception("lookup.toolblockID doesn't appear to be a valid block id"); + throw new DataFormatException("lookup.toolblockID doesn't appear to be a valid block id"); askRollbacks = config.getBoolean("questioner.askRollbacks", true); askRedos = config.getBoolean("questioner.askRedos", true); askClearLogs = config.getBoolean("questioner.askClearLogs", true); + askSavequeueBeforeRollback = config.getBoolean("questioner.askSavequeueBeforeRollback", true); final List worldNames = config.getStringList("loggedWorlds", null); final List worldTables = config.getStringList("tables", null); tables = new HashMap(); if (worldNames == null || worldTables == null || worldNames.size() == 0 || worldNames.size() != worldTables.size()) - throw new Exception("worldNames or worldTables not set properly"); + throw new DataFormatException("worldNames or worldTables not set properly"); for (int i = 0; i < worldNames.size(); i++) tables.put(worldNames.get(i).hashCode(), worldTables.get(i)); } diff --git a/src/de/diddiz/LogBlock/Consumer.java b/src/de/diddiz/LogBlock/Consumer.java index ca63e08..90e3bed 100644 --- a/src/de/diddiz/LogBlock/Consumer.java +++ b/src/de/diddiz/LogBlock/Consumer.java @@ -1,5 +1,8 @@ package de.diddiz.LogBlock; +import static de.diddiz.util.BukkitUtils.compressInventory; +import static de.diddiz.util.BukkitUtils.getEntityName; +import static de.diddiz.util.BukkitUtils.rawData; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; @@ -20,7 +23,6 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; -import de.diddiz.util.BukkitUtils; public class Consumer extends TimerTask { @@ -160,9 +162,9 @@ public class Consumer extends TimerTask * Logs a container block break. The block type before is assumed to be o (air). All content is assumed to be taken. */ public void queueContainerBreak(String playerName, Location loc, int type, byte data, Inventory inv) { - final ItemStack[] items = BukkitUtils.compressInventory(inv.getContents()); + final ItemStack[] items = compressInventory(inv.getContents()); for (final ItemStack item : items) - queueChestAccess(playerName, loc, type, (short)item.getTypeId(), (short)(item.getAmount() * -1), BukkitUtils.rawData(item)); + queueChestAccess(playerName, loc, type, (short)item.getTypeId(), (short)(item.getAmount() * -1), rawData(item)); queueBlockBreak(playerName, loc, type, data); } @@ -182,7 +184,7 @@ public class Consumer extends TimerTask weapon = ((Player)killer).getItemInHand().getTypeId(); lastAttackedEntity.put(killer.getEntityId(), victim.getEntityId()); lastAttackTime.put(killer.getEntityId(), System.currentTimeMillis()); - queueKill(victim.getWorld(), BukkitUtils.getEntityName(killer), BukkitUtils.getEntityName(victim), weapon); + queueKill(victim.getWorld(), getEntityName(killer), getEntityName(victim), weapon); } /** @@ -421,7 +423,10 @@ public class Consumer extends TimerTask ChestAccess(short itemType, short itemAmount, byte itemData) { this.itemType = itemType; this.itemAmount = itemAmount; - this.itemData = itemData; + if (itemData < 0) + this.itemData = 0; + else + this.itemData = itemData; } } diff --git a/src/de/diddiz/LogBlock/HistoryFormatter.java b/src/de/diddiz/LogBlock/HistoryFormatter.java new file mode 100644 index 0000000..885a840 --- /dev/null +++ b/src/de/diddiz/LogBlock/HistoryFormatter.java @@ -0,0 +1,67 @@ +package de.diddiz.LogBlock; + +import static de.diddiz.util.BukkitUtils.getMaterialName; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.text.SimpleDateFormat; +import de.diddiz.LogBlock.QueryParams.SummarizationMode; + +public class HistoryFormatter +{ + private final SimpleDateFormat formatter = new SimpleDateFormat("MM-dd HH:mm:ss"); + private final SummarizationMode sum; + + HistoryFormatter(SummarizationMode sum) { + this.sum = sum; + } + + String format(ResultSet rs) throws SQLException { + if (sum == SummarizationMode.NONE) { + final StringBuilder msg = new StringBuilder(formatter.format(rs.getTimestamp("date")) + " " + rs.getString("playername") + " "); + final int type = rs.getInt("type"); + final int replaced = rs.getInt("replaced"); + final String signtext; + if ((type == 63 || type == 68 || replaced == 63 || replaced == 68) && (signtext = rs.getString("signtext")) != null) { + final String action; + if (type == 0) + action = "destroyed "; + else + action = "created "; + if (!signtext.contains("\0")) + msg.append(action + signtext); + else + msg.append(action + "sign [" + signtext.replace("\0", "] [") + "]"); + } else if (type == replaced) { + if (type == 0) + msg.append("did a unspecified action"); + else if (type == 23 || type == 54 || type == 61) { + final int itemType = rs.getInt("itemtype"); + final int itemAmount = rs.getInt("itemamount"); + if (itemType == 0 || itemAmount == 0) + msg.append("looked inside " + getMaterialName(type)); + else if (itemAmount < 0) + msg.append("took " + itemAmount * -1 + "x " + getMaterialName(itemType)); + else + msg.append("put in " + itemAmount + "x " + getMaterialName(itemType)); + } + } else if (type == 0) + msg.append("destroyed " + getMaterialName(replaced)); + else if (replaced == 0) + msg.append("created " + getMaterialName(type)); + else + msg.append("replaced " + getMaterialName(replaced) + " with " + getMaterialName(type)); + return msg.toString(); + } else if (sum == SummarizationMode.TYPES) + return fillWithSpaces(rs.getInt("created")) + fillWithSpaces(rs.getInt("destroyed")) + getMaterialName(rs.getInt("type")); + else + return fillWithSpaces(rs.getInt("created")) + fillWithSpaces(rs.getInt("destroyed")) + rs.getString("playername"); + } + + private static String fillWithSpaces(Integer number) { + final StringBuilder filled = new StringBuilder(number.toString()); + final int neededSpaces = (36 - filled.length() * 6) / 4; + for (int i = 0; i < neededSpaces; i++) + filled.append(' '); + return filled.toString(); + } +} diff --git a/src/de/diddiz/LogBlock/LBChestAccessListener.java b/src/de/diddiz/LogBlock/LBChestAccessListener.java index 2324527..0704b43 100644 --- a/src/de/diddiz/LogBlock/LBChestAccessListener.java +++ b/src/de/diddiz/LogBlock/LBChestAccessListener.java @@ -1,5 +1,8 @@ package de.diddiz.LogBlock; +import static de.diddiz.util.BukkitUtils.compareInventories; +import static de.diddiz.util.BukkitUtils.compressInventory; +import static de.diddiz.util.BukkitUtils.rawData; import java.util.HashMap; import org.bukkit.Location; import org.bukkit.block.BlockState; @@ -8,7 +11,6 @@ import org.bukkit.inventory.ItemStack; import org.bukkitcontrib.event.inventory.InventoryCloseEvent; import org.bukkitcontrib.event.inventory.InventoryListener; import org.bukkitcontrib.event.inventory.InventoryOpenEvent; -import de.diddiz.util.BukkitUtils; class LBChestAccessListener extends InventoryListener { @@ -25,10 +27,10 @@ class LBChestAccessListener extends InventoryListener final String playerName = event.getPlayer().getName(); final Location loc = event.getLocation(); final ItemStack[] before = containers.get(playerName.hashCode()); - final ItemStack[] after = BukkitUtils.compressInventory(event.getInventory().getContents()); - final ItemStack[] diff = BukkitUtils.compareInventories(before, after); + final ItemStack[] after = compressInventory(event.getInventory().getContents()); + final ItemStack[] diff = compareInventories(before, after); for (final ItemStack item : diff) - consumer.queueChestAccess(playerName, loc, loc.getWorld().getBlockTypeIdAt(loc), (short)item.getTypeId(), (short)item.getAmount(), BukkitUtils.rawData(item)); + consumer.queueChestAccess(playerName, loc, loc.getWorld().getBlockTypeIdAt(loc), (short)item.getTypeId(), (short)item.getAmount(), rawData(item)); containers.remove(playerName.hashCode()); } } @@ -38,7 +40,7 @@ class LBChestAccessListener extends InventoryListener if (!event.isCancelled() && event.getLocation() != null) { final BlockState state = event.getLocation().getWorld().getBlockAt(event.getLocation()).getState(); if (state instanceof ContainerBlock) - containers.put(event.getPlayer().getName().hashCode(), BukkitUtils.compressInventory(((ContainerBlock)state).getInventory().getContents())); + containers.put(event.getPlayer().getName().hashCode(), compressInventory(((ContainerBlock)state).getInventory().getContents())); } } } diff --git a/src/de/diddiz/LogBlock/LBToolListener.java b/src/de/diddiz/LogBlock/LBToolListener.java index e129820..af4d0f3 100644 --- a/src/de/diddiz/LogBlock/LBToolListener.java +++ b/src/de/diddiz/LogBlock/LBToolListener.java @@ -44,7 +44,7 @@ class LBToolListener extends PlayerListener if (tables.get(player.getWorld().getName().hashCode()) != null) { try { final QueryParams params = logblock.getSession(player.getName()).toolQuery; - params.setLocation(event.getClickedBlock().getLocation()); + params.setLocation(event.getClickedBlock().getFace(event.getBlockFace()).getLocation()); handler.new CommandLookup(player, params); } catch (final Exception ex) { player.sendMessage(ChatColor.RED + ex.getMessage()); diff --git a/src/de/diddiz/LogBlock/LogBlock.java b/src/de/diddiz/LogBlock/LogBlock.java index b2e8230..7c09770 100644 --- a/src/de/diddiz/LogBlock/LogBlock.java +++ b/src/de/diddiz/LogBlock/LogBlock.java @@ -1,13 +1,10 @@ package de.diddiz.LogBlock; +import static de.diddiz.util.Utils.downloadIfNotExists; import java.io.File; -import java.io.FileNotFoundException; -import java.io.IOException; import java.net.URL; import java.sql.Connection; -import java.sql.DatabaseMetaData; import java.sql.SQLException; -import java.sql.Statement; import java.util.HashMap; import java.util.Map; import java.util.Timer; @@ -24,8 +21,7 @@ import org.bukkit.plugin.java.JavaPlugin; import com.nijiko.permissions.PermissionHandler; import com.nijikokun.bukkit.Permissions.Permissions; import de.diddiz.LogBlock.QueryParams.BlockChangeType; -import de.diddiz.util.ConnectionPool; -import de.diddiz.util.Utils; +import de.diddiz.util.MySQLConnectionPool; // TODO Add painting logging // TODO Add Button, lever etc logging @@ -34,7 +30,7 @@ public class LogBlock extends JavaPlugin { private Logger log; private Config config; - private ConnectionPool pool; + private MySQLConnectionPool pool; private Consumer consumer = null; private CommandsHandler commandsHandler; private Timer timer = null; @@ -59,35 +55,13 @@ public class LogBlock extends JavaPlugin log = getServer().getLogger(); try { config = new Config(this); - } catch (final Exception ex) { - log.log(Level.SEVERE, "[LogBlock] Exception while reading config:", ex); - errorAtLoading = true; - return; - } - final File file = new File("lib/mysql-connector-java-bin.jar"); - try { - if (!file.exists() || file.length() == 0) { - log.info("[LogBlock] Downloading " + file.getName() + "..."); - Utils.download(new URL("http://diddiz.insane-architects.net/download/mysql-connector-java-bin.jar"), file); - } - if (!file.exists() || file.length() == 0) - throw new FileNotFoundException(file.getAbsolutePath() + file.getName()); - } catch (final IOException e) { - log.log(Level.SEVERE, "[LogBlock] Error while downloading " + file.getName() + "."); - errorAtLoading = true; - return; - } - try { + downloadIfNotExists(log, new File("lib/mysql-connector-java-bin.jar"), new URL("http://diddiz.insane-architects.net/download/mysql-connector-java-bin.jar")); log.info("[LogBlock] Connecting to " + config.user + "@" + config.url + "..."); - pool = new ConnectionPool(config.url, config.user, config.password); + pool = new MySQLConnectionPool(config.url, config.user, config.password); getConnection().close(); + new Updater(this).checkTables(); } catch (final Exception ex) { - log.log(Level.SEVERE, "[LogBlock] Exception while checking database connection", ex); - errorAtLoading = true; - return; - } - if (!checkTables()) { - log.log(Level.SEVERE, "[LogBlock] Errors while checking tables. They may not exist."); + log.log(Level.SEVERE, "[LogBlock] Error while loading: ", ex); errorAtLoading = true; return; } @@ -184,64 +158,6 @@ public class LogBlock extends JavaPlugin log.info("LogBlock disabled."); } - private boolean checkTables() { - final Connection conn = getConnection(); - Statement state = null; - if (conn == null) - return false; - try { - final DatabaseMetaData dbm = conn.getMetaData(); - conn.setAutoCommit(true); - state = conn.createStatement(); - if (!dbm.getTables(null, null, "lb-players", null).next()) { - log.log(Level.INFO, "[LogBlock] Crating table lb-players."); - state.execute("CREATE TABLE `lb-players` (playerid SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, playername varchar(32) NOT NULL DEFAULT '-', PRIMARY KEY (playerid), UNIQUE (playername))"); - if (!dbm.getTables(null, null, "lb-players", null).next()) - return false; - } - for (final String table : config.tables.values()) { - if (!dbm.getTables(null, null, table, null).next()) { - log.log(Level.INFO, "[LogBlock] Crating table " + table + "."); - state.execute("CREATE TABLE `" + table + "` (id INT NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid SMALLINT UNSIGNED NOT NULL, replaced TINYINT UNSIGNED NOT NULL, type TINYINT UNSIGNED NOT NULL, data TINYINT UNSIGNED NOT NULL, x SMALLINT NOT NULL, y TINYINT UNSIGNED NOT NULL, z SMALLINT NOT NULL, PRIMARY KEY (id), KEY coords (y, x, z), KEY date (date))"); - if (!dbm.getTables(null, null, table, null).next()) - return false; - } - if (!dbm.getTables(null, null, table + "-sign", null).next()) { - log.log(Level.INFO, "[LogBlock] Crating table " + table + "-sign."); - state.execute("CREATE TABLE `" + table + "-sign` (id INT NOT NULL, signtext TEXT, PRIMARY KEY (id));"); - if (!dbm.getTables(null, null, table + "-sign", null).next()) - return false; - } - if (dbm.getTables(null, null, table + "-chest", null).next() && state.executeQuery("SELECT * FROM `" + table + "-chest` LIMIT 1").getMetaData().getColumnCount() != 4) // Chest table update - state.execute("DROP TABLE `" + table + "-chest`"); - if (!dbm.getTables(null, null, table + "-chest", null).next()) { - log.log(Level.INFO, "[LogBlock] Crating table " + table + "-chest."); - state.execute("CREATE TABLE `" + table + "-chest` (id INT NOT NULL, itemtype SMALLINT UNSIGNED NOT NULL, itemamount SMALLINT NOT NULL, itemdata TINYINT UNSIGNED NOT NULL, PRIMARY KEY (id))"); - if (!dbm.getTables(null, null, table + "-chest", null).next()) - return false; - } - if (config.logKills && !dbm.getTables(null, null, table + "-kills", null).next()) { - log.log(Level.INFO, "[LogBlock] Crating table " + table + "-kills."); - state.execute("CREATE TABLE `" + table + "-kills` (id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer SMALLINT UNSIGNED, victim SMALLINT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, PRIMARY KEY (id));"); - if (!dbm.getTables(null, null, table + "-kills", null).next()) - return false; - } - } - return true; - } catch (final SQLException ex) { - log.log(Level.SEVERE, "[LogBlock] SQL exception while checking tables", ex); - } finally { - try { - if (state != null) - state.close(); - conn.close(); - } catch (final SQLException ex) { - log.log(Level.SEVERE, "[LogBlock] SQL exception on close", ex); - } - } - return false; - } - boolean hasPermission(CommandSender sender, String permission) { if (permissions != null && sender instanceof Player) return permissions.permission((Player)sender, permission); diff --git a/src/de/diddiz/LogBlock/QueryParams.java b/src/de/diddiz/LogBlock/QueryParams.java index 6e2fc8e..037a03c 100644 --- a/src/de/diddiz/LogBlock/QueryParams.java +++ b/src/de/diddiz/LogBlock/QueryParams.java @@ -1,5 +1,11 @@ package de.diddiz.LogBlock; +import static de.diddiz.util.BukkitUtils.friendlyWorldname; +import static de.diddiz.util.BukkitUtils.getBlockEquivalents; +import static de.diddiz.util.BukkitUtils.getMaterialName; +import static de.diddiz.util.BukkitUtils.getSenderName; +import static de.diddiz.util.Utils.isInt; +import static de.diddiz.util.Utils.parseTimeSpec; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; @@ -14,8 +20,6 @@ import org.bukkit.plugin.Plugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.selections.CuboidSelection; import com.sk89q.worldedit.bukkit.selections.Selection; -import de.diddiz.util.BukkitUtils; -import de.diddiz.util.Utils; public class QueryParams implements Cloneable { @@ -90,7 +94,7 @@ public class QueryParams implements Cloneable final StringBuilder title = new StringBuilder(); if (!types.isEmpty()) { for (int i = 0; i < types.size(); i++) - title.append(BukkitUtils.getMaterialName(types.get(i)) + ", "); + title.append(getMaterialName(types.get(i)) + ", "); title.deleteCharAt(title.length() - 2); } else title.append("Block "); @@ -116,7 +120,7 @@ public class QueryParams implements Cloneable title.append("at " + loc.getBlockX() + ":" + loc.getBlockY() + ":" + loc.getBlockZ() + " "); else if (sel != null) title.append("inside selection "); - title.append("in " + BukkitUtils.friendlyWorldname(world.getName())); + title.append("in " + friendlyWorldname(world.getName())); title.setCharAt(0, String.valueOf(title.charAt(0)).toUpperCase().toCharArray()[0]); return title.toString(); } @@ -204,10 +208,9 @@ public class QueryParams implements Cloneable Player player = null; if (sender instanceof Player) player = (Player)sender; - final String name = BukkitUtils.getSenderName(sender); final Session session; if (!prepareToolQuery) - session = logblock.getSession(name); + session = logblock.getSession(getSenderName(sender)); else session = null; if (player != null && world == null) @@ -224,7 +227,7 @@ public class QueryParams implements Cloneable throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); for (final String playerName : values) if (playerName.length() > 0) - players.add(playerName); + players.add(playerName.replace("\\", "\\\\").replace("'", "\\'")); } else if (param.equals("block") || param.equals("type")) { if (values == null || values.length < 1) throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); @@ -242,7 +245,7 @@ public class QueryParams implements Cloneable if (!prepareToolQuery) loc = player.getLocation(); } else { - if (!Utils.isInt(values[0])) + if (!isInt(values[0])) throw new IllegalArgumentException("Not a number: '" + values[0] + "'"); radius = Integer.parseInt(values[0]); if (!prepareToolQuery) @@ -264,14 +267,14 @@ public class QueryParams implements Cloneable if (values == null) minutes = logblock.getConfig().defaultTime; else - minutes = Utils.parseTimeSpec(values); + minutes = parseTimeSpec(values); if (minutes == -1) throw new IllegalArgumentException("Faile to parse time spec for '" + param + "'"); } else if (param.equals("before")) { if (values == null) minutes = logblock.getConfig().defaultTime * -1; else - minutes = Utils.parseTimeSpec(values) * -1; + minutes = parseTimeSpec(values) * -1; if (minutes == 1) throw new IllegalArgumentException("Faile to parse time spec for '" + param + "'"); } else if (param.equals("sum")) { @@ -296,7 +299,7 @@ public class QueryParams implements Cloneable else if (param.equals("limit")) { if (values.length != 1) throw new IllegalArgumentException("Wrong count of arguments for '" + param + "'"); - if (!Utils.isInt(values[0])) + if (!isInt(values[0])) throw new IllegalArgumentException("Not a number: '" + values[0] + "'"); limit = Integer.parseInt(values[0]); } else if (param.equals("world")) { @@ -315,7 +318,7 @@ public class QueryParams implements Cloneable i += values.length; } if (types.size() > 0) - for (final Set equivalent : BukkitUtils.getBlockEquivalents()) { + for (final Set equivalent : getBlockEquivalents()) { boolean found = false; for (final Integer type : types) if (equivalent.contains(type)) { diff --git a/src/de/diddiz/LogBlock/Updater.java b/src/de/diddiz/LogBlock/Updater.java new file mode 100644 index 0000000..02243e1 --- /dev/null +++ b/src/de/diddiz/LogBlock/Updater.java @@ -0,0 +1,64 @@ +package de.diddiz.LogBlock; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.logging.Level; +import java.util.logging.Logger; + +class Updater +{ + private final Logger log; + private final LogBlock logblock; + + Updater(LogBlock logblock) { + this.logblock = logblock; + log = logblock.getServer().getLogger(); + } + + void checkTables() throws SQLException { + final Connection conn = logblock.getConnection(); + if (conn == null) + throw new SQLException("No connection"); + final Statement state = conn.createStatement(); + final DatabaseMetaData dbm = conn.getMetaData(); + conn.setAutoCommit(true); + if (!dbm.getTables(null, null, "lb-players", null).next()) { + log.log(Level.INFO, "[LogBlock] Crating table lb-players."); + state.execute("CREATE TABLE `lb-players` (playerid SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, playername varchar(32) NOT NULL DEFAULT '-', PRIMARY KEY (playerid), UNIQUE (playername))"); + if (!dbm.getTables(null, null, "lb-players", null).next()) + throw new SQLException("Table lb-players not found"); + } + for (final String table : logblock.getConfig().tables.values()) { + if (!dbm.getTables(null, null, table, null).next()) { + log.log(Level.INFO, "[LogBlock] Crating table " + table + "."); + state.execute("CREATE TABLE `" + table + "` (id INT NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid SMALLINT UNSIGNED NOT NULL, replaced TINYINT UNSIGNED NOT NULL, type TINYINT UNSIGNED NOT NULL, data TINYINT UNSIGNED NOT NULL, x SMALLINT NOT NULL, y TINYINT UNSIGNED NOT NULL, z SMALLINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date))"); + if (!dbm.getTables(null, null, table, null).next()) + throw new SQLException("Table " + table + " not found"); + } + if (!dbm.getTables(null, null, table + "-sign", null).next()) { + log.log(Level.INFO, "[LogBlock] Crating table " + table + "-sign."); + state.execute("CREATE TABLE `" + table + "-sign` (id INT NOT NULL, signtext TEXT, PRIMARY KEY (id));"); + if (!dbm.getTables(null, null, table + "-sign", null).next()) + throw new SQLException("Table " + table + "-sign not found"); + } + if (dbm.getTables(null, null, table + "-chest", null).next() && state.executeQuery("SELECT * FROM `" + table + "-chest` LIMIT 1").getMetaData().getColumnCount() != 4) // Chest table update + state.execute("DROP TABLE `" + table + "-chest`"); + if (!dbm.getTables(null, null, table + "-chest", null).next()) { + log.log(Level.INFO, "[LogBlock] Crating table " + table + "-chest."); + state.execute("CREATE TABLE `" + table + "-chest` (id INT NOT NULL, itemtype SMALLINT UNSIGNED NOT NULL, itemamount SMALLINT NOT NULL, itemdata TINYINT UNSIGNED NOT NULL, PRIMARY KEY (id))"); + if (!dbm.getTables(null, null, table + "-chest", null).next()) + throw new SQLException("Table " + table + "-chest not found"); + } + if (logblock.getConfig().logKills && !dbm.getTables(null, null, table + "-kills", null).next()) { + log.log(Level.INFO, "[LogBlock] Crating table " + table + "-kills."); + state.execute("CREATE TABLE `" + table + "-kills` (id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer SMALLINT UNSIGNED, victim SMALLINT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, PRIMARY KEY (id));"); + if (!dbm.getTables(null, null, table + "-kills", null).next()) + throw new SQLException("Table " + table + "-kills not found"); + } + } + state.close(); + conn.close(); + } +} diff --git a/src/de/diddiz/LogBlock/WorldEditor.java b/src/de/diddiz/LogBlock/WorldEditor.java index 6099053..6397239 100644 --- a/src/de/diddiz/LogBlock/WorldEditor.java +++ b/src/de/diddiz/LogBlock/WorldEditor.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock; +import static de.diddiz.util.BukkitUtils.equalTypes; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Logger; import org.bukkit.World; @@ -11,7 +12,6 @@ import org.bukkit.block.Sign; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.ItemStack; import org.bukkit.material.Bed; -import de.diddiz.util.BukkitUtils; public class WorldEditor implements Runnable { @@ -144,7 +144,7 @@ public class WorldEditor implements Runnable return PerformResult.SUCCESS; } else return PerformResult.NO_ACTION; - if (!(BukkitUtils.equalTypes(block.getTypeId(), type) || config.replaceAnyway.contains(block.getTypeId()))) + if (!(equalTypes(block.getTypeId(), type) || config.replaceAnyway.contains(block.getTypeId()))) return PerformResult.NO_ACTION; if (state instanceof ContainerBlock) { ((ContainerBlock)state).getInventory().clear(); @@ -156,8 +156,12 @@ public class WorldEditor implements Runnable if (signtext != null && (curtype == 63 || curtype == 68)) { final Sign sign = (Sign)block.getState(); final String[] lines = signtext.split("\0"); - for (int i = 0; i < 4; i++) - sign.setLine(i, lines[i]); + try { + for (int i = 0; i < 4; i++) + sign.setLine(i, lines[i]); + } catch (final IndexOutOfBoundsException ex) { + return PerformResult.ERROR; + } if (!sign.update()) return PerformResult.ERROR; } else if (curtype == 26) { diff --git a/src/de/diddiz/util/BukkitUtils.java b/src/de/diddiz/util/BukkitUtils.java index 01c17b6..a3f4548 100644 --- a/src/de/diddiz/util/BukkitUtils.java +++ b/src/de/diddiz/util/BukkitUtils.java @@ -34,14 +34,15 @@ public class BukkitUtils public static ItemStack[] compareInventories(ItemStack[] items1, ItemStack[] items2) { final ItemStackComparator comperator = new ItemStackComparator(); final ArrayList diff = new ArrayList(); + final int l1 = items1.length, l2 = items2.length; int c1 = 0, c2 = 0; - while (c1 < items1.length || c2 < items2.length) { - if (c1 >= items1.length) { + while (c1 < l1 || c2 < l2) { + if (c1 >= l1) { diff.add(items2[c2]); c2++; continue; } - if (c2 >= items2.length) { + if (c2 >= l2) { items1[c1].setAmount(items1[c1].getAmount() * -1); diff.add(items1[c1]); c1++; @@ -147,7 +148,7 @@ public class BukkitUtils return item.getData().getData(); } - private static class ItemStackComparator implements Comparator + public static class ItemStackComparator implements Comparator { @Override public int compare(ItemStack a, ItemStack b) { diff --git a/src/de/diddiz/util/ConnectionPool.java b/src/de/diddiz/util/MySQLConnectionPool.java similarity index 94% rename from src/de/diddiz/util/ConnectionPool.java rename to src/de/diddiz/util/MySQLConnectionPool.java index 1bb7231..80db572 100644 --- a/src/de/diddiz/util/ConnectionPool.java +++ b/src/de/diddiz/util/MySQLConnectionPool.java @@ -22,7 +22,7 @@ import java.util.Map; import java.util.Properties; import java.util.Vector; -public class ConnectionPool implements Closeable +public class MySQLConnectionPool implements Closeable { private final static int poolsize = 10; private final static long timeToLive = 300000; @@ -30,7 +30,7 @@ public class ConnectionPool implements Closeable private final ConnectionReaper reaper; private final String url, user, password; - public ConnectionPool(String url, String user, String password) throws ClassNotFoundException { + public MySQLConnectionPool(String url, String user, String password) throws ClassNotFoundException { Class.forName("com.mysql.jdbc.Driver"); this.url = url; this.user = user; diff --git a/src/de/diddiz/util/Utils.java b/src/de/diddiz/util/Utils.java index 9f7ae9e..7f73d13 100644 --- a/src/de/diddiz/util/Utils.java +++ b/src/de/diddiz/util/Utils.java @@ -2,6 +2,7 @@ package de.diddiz.util; import java.io.BufferedOutputStream; import java.io.File; +import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; @@ -9,23 +10,41 @@ import java.io.OutputStream; import java.net.URL; import java.text.ParseException; import java.text.SimpleDateFormat; +import java.util.logging.Logger; public class Utils { - public static void download(URL u, File file) throws IOException { + public static void download(Logger log, URL url, File file) throws IOException { if (!file.getParentFile().exists()) file.getParentFile().mkdir(); if (file.exists()) file.delete(); file.createNewFile(); - final InputStream in = u.openStream(); + final int size = url.openConnection().getContentLength(); + log.info("Downloading " + file.getName() + " (" + size / 1024 + "kb) ..."); + final InputStream in = url.openStream(); final OutputStream out = new BufferedOutputStream(new FileOutputStream(file)); final byte[] buffer = new byte[1024]; - int len; - while ((len = in.read(buffer)) >= 0) + int len, downloaded = 0, msgs = 0; + final long start = System.currentTimeMillis(); + while ((len = in.read(buffer)) >= 0) { out.write(buffer, 0, len); + downloaded += len; + if ((int)((System.currentTimeMillis() - start) / 500) > msgs) { + log.info((int)((double)downloaded / (double)size * 100d) + "%"); + msgs++; + } + } in.close(); out.close(); + log.info("Download finished"); + } + + public static void downloadIfNotExists(Logger log, File file, URL url) throws IOException { + if (!file.exists() || file.length() == 0) + Utils.download(log, url, file); + if (!file.exists() || file.length() == 0) + throw new FileNotFoundException(file.getAbsolutePath() + file.getName()); } public static boolean isInt(String str) { diff --git a/src/plugin.yml b/src/plugin.yml index 209fcb4..5f7bb70 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -1,5 +1,5 @@ name: LogBlock -version: '1.00rc3' +version: '1.00final' author: DiddiZ, bootswithdefer website: http://www.diddiz.de/minecraft/ main: de.diddiz.LogBlock.LogBlock