This commit is contained in:
Robin Kupper
2011-05-22 04:01:43 +02:00
parent c5cfa5fd87
commit 6c404d8ca8
25 changed files with 1591 additions and 1739 deletions

View File

@@ -1,95 +0,0 @@
package de.diddiz.LogBlock;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.ChatColor;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.entity.Player;
public class AreaBlockSearch implements Runnable
{
private final Logger log;
private final Player player;
private final Location location;
private final int type;
private final int size;
private final Connection conn;
private final String table;
AreaBlockSearch(LogBlock logblock, Player player, int type, int size) {
this.player = player;
location = player.getLocation();
this.type = type;
this.size = size;
log = logblock.getServer().getLogger();
conn = logblock.getConnection();
table = logblock.getConfig().tables.get(player.getWorld().getName().hashCode());
}
@Override
public void run() {
boolean hist = false;
PreparedStatement ps = null;
ResultSet rs = null;
final SimpleDateFormat formatter = new SimpleDateFormat("MM-dd HH:mm:ss");
try {
if (conn == null) {
player.sendMessage(ChatColor.RED + "Failed to create database connection");
return;
}
if (table == null) {
player.sendMessage(ChatColor.RED + "This world isn't logged");
return;
}
conn.setAutoCommit(false);
ps = conn.prepareStatement("SELECT * FROM `" + table + "` INNER JOIN `lb-players` USING (playerid) WHERE (type = ? or replaced = ?) and y > ? and y < ? and x > ? and x < ? and z > ? and z < ? order by date desc limit 10");
ps.setInt(1, type);
ps.setInt(2, type);
ps.setInt(3, location.getBlockY() - size);
ps.setInt(4, location.getBlockY() + size);
ps.setInt(5, location.getBlockX() - size);
ps.setInt(6, location.getBlockX() + size);
ps.setInt(7, location.getBlockZ() - size);
ps.setInt(8, location.getBlockZ() + size);
rs = ps.executeQuery();
player.sendMessage(ChatColor.DARK_AQUA + "Block history for " + getMaterialName(type) + " within " + size + " blocks of " + location.getBlockX() + ", " + location.getBlockY() + ", " + location.getBlockZ() + ": ");
while (rs.next()) {
String msg = formatter.format(rs.getTimestamp("date")) + " " + rs.getString("playername") + " (" + rs.getInt("x") + ", " + rs.getInt("y") + ", " + rs.getInt("z") + ") ";
if (rs.getInt("type") == 0)
msg = msg + "destroyed " + getMaterialName(rs.getInt("replaced"));
else if (rs.getInt("replaced") == 0)
msg = msg + "created " + getMaterialName(rs.getInt("type"));
else
msg = msg + "replaced " + getMaterialName(rs.getInt("replaced")) + " with " + getMaterialName(rs.getInt("type"));
player.sendMessage(ChatColor.GOLD + msg);
hist = true;
}
if (!hist)
player.sendMessage(ChatColor.DARK_AQUA + "None.");
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock AreaBlockSearch] SQL exception", ex);
} finally {
try {
if (rs != null)
rs.close();
if (ps != null)
ps.close();
if (conn != null)
conn.close();
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock AreaBlockSearch] SQL exception on close", ex);
}
}
}
private String getMaterialName(int type) {
return Material.getMaterial(type).toString().toLowerCase().replace('_', ' ');
}
}

View File

@@ -1,78 +0,0 @@
package de.diddiz.LogBlock;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
public class AreaStats implements Runnable
{
private final Logger log;
private final Player player;
private final int size;
private final Connection conn;
private final String table;
AreaStats(LogBlock logblock, Player player, int size) {
this.player = player;
this.size = size;
log = logblock.getServer().getLogger();
conn = logblock.getConnection();
table = logblock.getConfig().tables.get(player.getWorld().getName().hashCode());
}
@Override
public void run() {
PreparedStatement ps = null;
ResultSet rs = null;
try {
if (conn == null) {
player.sendMessage(ChatColor.RED + "Failed to create database connection");
return;
}
if (table == null) {
player.sendMessage(ChatColor.RED + "This world isn't logged");
return;
}
conn.setAutoCommit(false);
ps = conn.prepareStatement("SELECT `playername`, SUM(`created`) AS `created`, SUM(`destroyed`) AS `destroyed` FROM ((SELECT `playerid`, count(`type`) AS `created`, 0 AS `destroyed` FROM `" + table + "` WHERE `type` > 0 AND x > ? AND x < ? AND z > ? AND z < ? AND `type` != `replaced` GROUP BY `playerid`) UNION (SELECT `playerid`, 0 AS `created`, count(`replaced`) AS `destroyed` FROM `" + table + "` WHERE `replaced` > 0 AND x > ? AND x < ? AND z > ? AND z < ? AND `type` != `replaced` GROUP BY `playerid`)) AS t INNER JOIN `lb-players` USING (`playerid`) GROUP BY `playerid` ORDER BY SUM(`created`) + SUM(`destroyed`) DESC LIMIT 15");
ps.setInt(1, player.getLocation().getBlockX()-size);
ps.setInt(2, player.getLocation().getBlockX()+size);
ps.setInt(3, player.getLocation().getBlockZ()-size);
ps.setInt(4, player.getLocation().getBlockZ()+size);
ps.setInt(5, player.getLocation().getBlockX()-size);
ps.setInt(6, player.getLocation().getBlockX()+size);
ps.setInt(7, player.getLocation().getBlockZ()-size);
ps.setInt(8, player.getLocation().getBlockZ()+size);
rs = ps.executeQuery();
player.sendMessage(ChatColor.DARK_AQUA + "Within " + size + " blocks of you: ");
if (!rs.next())
player.sendMessage(ChatColor.DARK_AQUA + "No results found.");
else {
player.sendMessage(ChatColor.GOLD + String.format("%-6s %-6s %s", "Creat", "Destr", "Player"));
rs.beforeFirst();
while (rs.next()) {
player.sendMessage(ChatColor.GOLD + String.format("%-6d %-6d %s", rs.getInt("created"), rs.getInt("destroyed"), rs.getString("playername")));
}
}
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock AreaStats] SQL exception", ex);
} finally {
try {
if (rs != null)
rs.close();
if (ps != null)
ps.close();
if (conn != null)
conn.close();
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock AreaStats] SQL exception on close", ex);
}
}
}
}

View File

@@ -1,93 +0,0 @@
package de.diddiz.LogBlock;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
public class BlockStats implements Runnable
{
private final Logger log;
private final Connection conn;
private final String table;
private final Player player;
private final Block block;
BlockStats(LogBlock logblock, Player player, Block block) {
log = logblock.getServer().getLogger();
conn = logblock.getConnection();
table = logblock.getConfig().tables.get(player.getWorld().getName().hashCode());
this.player = player;
this.block = block;
}
@Override
public void run() {
boolean hist = false;
PreparedStatement ps = null;
ResultSet rs = null;
final SimpleDateFormat formatter = new SimpleDateFormat("MM-dd HH:mm:ss");
try {
if (conn == null) {
player.sendMessage(ChatColor.RED + "Failed to create database connection");
return;
}
if (table == null) {
player.sendMessage(ChatColor.RED + "This world isn't logged");
return;
}
conn.setAutoCommit(false);
ps = conn.prepareStatement("SELECT date, replaced, type, signtext, playername FROM `" + table + "` LEFT JOIN `" + table + "-sign` USING (id) INNER JOIN `lb-players` USING (playerid) WHERE x = ? AND y = ? AND z = ? ORDER BY date DESC LIMIT 15");
ps.setInt(1, block.getX());
ps.setInt(2, block.getY());
ps.setInt(3, block.getZ());
rs = ps.executeQuery();
player.sendMessage(ChatColor.DARK_AQUA + "Block history (" + block.getX() + ", " + block.getY() + ", " + block.getZ() + "): ");
while (rs.next()) {
String msg = formatter.format(rs.getTimestamp("date")) + " " + rs.getString("playername") + " ";
final int type = rs.getInt("type");
final int replaced = rs.getInt("replaced");
if ((type == 63 || type == 68) && rs.getString("signtext") != null)
msg += "created " + rs.getString("signtext");
else if (type == replaced) {
if (type == 23 || type == 54 || type == 61)
msg += "looked inside " + getMaterialName(type);
} else if (type == 0)
msg += "destroyed " + getMaterialName(replaced);
else if (replaced == 0)
msg += "created " + getMaterialName(type);
else
msg += "replaced " + getMaterialName(replaced) + " with " + getMaterialName(type);
player.sendMessage(ChatColor.GOLD + msg);
hist = true;
}
if (!hist)
player.sendMessage(ChatColor.DARK_AQUA + "None.");
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock BlockStats] SQL exception", ex);
} finally {
try {
if (rs != null)
rs.close();
if (ps != null)
ps.close();
if (conn != null)
conn.close();
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock BlockStats] SQL exception on close", ex);
}
}
}
private String getMaterialName(int type) {
return Material.getMaterial(type).toString().toLowerCase().replace('_', ' ');
}
}

View File

@@ -1,84 +0,0 @@
package de.diddiz.LogBlock;
import java.io.File;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ClearLog implements Runnable
{
private final Logger log;
private final Config config;
private final Connection conn;
private final File dumpFolder;
public ClearLog(LogBlock logblock) {
log = logblock.getServer().getLogger();
config = logblock.getConfig();
conn = logblock.getConnection();
dumpFolder = new File(logblock.getDataFolder(), "dumb");
}
@Override
public void run() {
Statement state = null;
try {
if (conn == null)
return;
dumpFolder.mkdirs();
state = conn.createStatement();
final String time = new SimpleDateFormat("yy-MM-dd-HH-mm-ss").format(System.currentTimeMillis() - config.keepLogDays*86400000L);
ResultSet rs;
for (final String table : config.tables.values()) {
rs = state.executeQuery("SELECT count(*) FROM `" + table + "` WHERE date < '" + time + "'");
rs.next();
int deleted = rs.getInt(1);
if (deleted > 0) {
if (config.dumpDeletedLog) {
try {
state.execute("SELECT * FROM `" + table + "` WHERE date < '" + time + "' INTO OUTFILE '" + new File(dumpFolder, table + "-" + time + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'");
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock ClearLog] Error while dumping log. Make sure your MySQL user has access to the LogBLock folder, or disable clearlog.dumpDeletedLog.", ex);
return;
}
}
state.execute("DELETE FROM `" + table + "` WHERE date < '" + time + "'");
log.info("[LogBlock] 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");
rs.next();
deleted = rs.getInt(1);
if (deleted > 0) {
if (config.dumpDeletedLog)
state.execute("SELECT id, signtext FROM `" + table + "-sign` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, table + "-sign-" + time + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'");
state.execute("DELETE `" + table + "-sign` FROM `" + table + "-sign` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL;");
log.info("[LogBlock] Cleared out table " + table + "-sign. Deleted " + deleted + " entries.");
}
rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-chest` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL");
rs.next();
deleted = rs.getInt(1);
if (deleted > 0) {
if (config.dumpDeletedLog)
state.execute("SELECT id, intype, inamount, outtype, outamount FROM `" + table + "-chest` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, table + "-chest-" + time + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'");
state.execute("DELETE `" + table + "-chest` FROM `" + table + "-chest` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL;");
log.info("[LogBlock] Cleared out table " + table + "-chest. Deleted " + deleted + " entries.");
}
}
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock] SQL exception", ex);
} finally {
try {
if (state != null)
state.close();
if (conn != null)
conn.close();
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock] SQL exception on close", ex);
}
}
}
}

View File

@@ -1,5 +1,6 @@
package de.diddiz.LogBlock; package de.diddiz.LogBlock;
import java.io.Closeable;
import java.io.File; import java.io.File;
import java.io.FileWriter; import java.io.FileWriter;
import java.io.IOException; import java.io.IOException;
@@ -8,184 +9,278 @@ import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.bukkit.ChatColor; import org.bukkit.ChatColor;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.command.Command; import org.bukkit.command.Command;
import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack; import org.bukkit.scheduler.BukkitScheduler;
import de.diddiz.LogBlock.QueryParams.BlockChangeType; import de.diddiz.LogBlock.QueryParams.BlockChangeType;
import de.diddiz.LogBlock.QueryParams.Order;
import de.diddiz.LogBlock.QueryParams.SummarizationMode; 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 public class CommandsHandler implements CommandExecutor
{ {
private final Logger log; private final Logger log;
private final LogBlock logblock; private final LogBlock logblock;
private final Config config; private final Config config;
private final BukkitScheduler scheduler;
private final LogBlockQuestioner questioner;
public CommandsHandler(LogBlock logblock) { CommandsHandler(LogBlock logblock) {
this.logblock = logblock; this.logblock = logblock;
log = logblock.getServer().getLogger(); log = logblock.getServer().getLogger();
config = logblock.getConfig(); config = logblock.getConfig();
scheduler = logblock.getServer().getScheduler();
questioner = (LogBlockQuestioner)logblock.getServer().getPluginManager().getPlugin("LogBlockQuestioner");
} }
@Override @Override
public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) { public boolean onCommand(CommandSender sender, Command cmd, String commandLabel, String[] args) {
if (!cmd.getName().equalsIgnoreCase("lb")) if (!cmd.getName().equalsIgnoreCase("lb"))
return false; return false;
if (args.length == 0) { if (args.length == 0) {
sender.sendMessage(ChatColor.LIGHT_PURPLE + "LogBlock v" + logblock.getDescription().getVersion() + " by DiddiZ"); sender.sendMessage(ChatColor.LIGHT_PURPLE + "LogBlock v" + logblock.getDescription().getVersion() + " by DiddiZ");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "Type /lb help for help"); sender.sendMessage(ChatColor.LIGHT_PURPLE + "Type /lb help for help");
} else if (args[0].equalsIgnoreCase("help")) { } else {
sender.sendMessage(ChatColor.LIGHT_PURPLE + "LogBlock Commands:"); final String command = args[0].toLowerCase();
if (logblock.checkPermission(sender, "logblock.me")) if (command.equals("help")) {
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb me"); sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Help:");
if (logblock.checkPermission(sender, "logblock.area")) { sender.sendMessage(ChatColor.GOLD + "For the commands list type '/lb commands'");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb area <radius>"); sender.sendMessage(ChatColor.GOLD + "For the parameters list type '/lb params'");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb world"); sender.sendMessage(ChatColor.GOLD + "For the list of permissions you got type '/lb permissions'");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb player [name] <radius>"); } else if (command.equals("commands")) {
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb block [type] <radius>"); sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Commands:");
} sender.sendMessage(ChatColor.GOLD + "/lb tool -- Gives you the lb tool");
if (logblock.checkPermission(sender, "logblock.rollback")) { sender.sendMessage(ChatColor.GOLD + "/lb tool [on|off] -- Enables/Disables tool");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb rollback [rollback mode]"); sender.sendMessage(ChatColor.GOLD + "/lb tool [params] -- Sets the tool lookup query");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb redo [redo mode]"); sender.sendMessage(ChatColor.GOLD + "/lb toolblock -- Analog to tool");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb writelogfile [player]"); sender.sendMessage(ChatColor.GOLD + "/lb hide -- Hides you from log");
} sender.sendMessage(ChatColor.GOLD + "/lb rollback [params] -- Rollback");
if (logblock.checkPermission(sender, "logblock.hide")) sender.sendMessage(ChatColor.GOLD + "/lb redo [params] -- Redo");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb hide"); sender.sendMessage(ChatColor.GOLD + "/lb tp [params] -- Teleports you to the location of griefing");
} else if (args[0].equalsIgnoreCase("tool")) { sender.sendMessage(ChatColor.GOLD + "/lb writelogfile [params] -- Writes a log file");
if (sender instanceof Player) { sender.sendMessage(ChatColor.GOLD + "/lb lookup [params] -- Lookup");
if (logblock.checkPermission(sender, "logblock.tool")) sender.sendMessage(ChatColor.GOLD + "/lb me -- Displays your stats");
giveTool((Player)sender, config.toolID); sender.sendMessage(ChatColor.GOLD + "Look at diddiz.insane-architects.net/logblock for the full commands reference");
else } else if (command.equals("params")) {
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Query Parameters:");
} else sender.sendMessage(ChatColor.GOLD + "Use doublequotes to escape a keyword: world \"world\"");
sender.sendMessage(ChatColor.RED + "You have to be a player."); sender.sendMessage(ChatColor.GOLD + "player [name1] <name2> <name3> -- List of players");
} else if (args[0].equalsIgnoreCase("toolblock")) { sender.sendMessage(ChatColor.GOLD + "block [type1] <type2> <type3> -- List of block types");
if (sender instanceof Player) { sender.sendMessage(ChatColor.GOLD + "created, destroyed -- Show only created/destroyed blocks");
if (logblock.checkPermission(sender, "logblock.toolblockID")) sender.sendMessage(ChatColor.GOLD + "chestaccess -- Show only chest accesses");
giveTool((Player)sender, config.toolblockID); sender.sendMessage(ChatColor.GOLD + "area <radius> -- Area around you");
else sender.sendMessage(ChatColor.GOLD + "selection, sel -- Inside current WorldEdit selection");
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); sender.sendMessage(ChatColor.GOLD + "world [worldname] -- Changes the world");
} else sender.sendMessage(ChatColor.GOLD + "time [number] [minutes|hours|days] -- Limits time");
sender.sendMessage(ChatColor.RED + "You have to be a player."); sender.sendMessage(ChatColor.GOLD + "since <dd.MM.yyyy> <HH:mm:ss> -- Limits time to a fixed point");
} else if (args[0].equalsIgnoreCase("hide")) { sender.sendMessage(ChatColor.GOLD + "limit <row count> -- Limits the result to count of rows");
if (sender instanceof Player) { sender.sendMessage(ChatColor.GOLD + "sum [none|blocks|players] -- Sums the result");
if (logblock.checkPermission(sender, "logblock.hide")) { sender.sendMessage(ChatColor.GOLD + "asc, desc -- Changes the order of the displayed log");
if (logblock.getConsumer().hide((Player)sender)) } else if (command.equals("permissions")) {
sender.sendMessage(ChatColor.GREEN + "You are now hided and won't appear in any log. Type '/lb hide' again to unhide"); sender.sendMessage(ChatColor.DARK_AQUA + "You've got the following permissions:");
if (logblock.hasPermission(sender, "logblock.tool"))
sender.sendMessage(ChatColor.GOLD + "logblock.tool");
if (logblock.hasPermission(sender, "logblock.toolblock"))
sender.sendMessage(ChatColor.GOLD + "logblock.toolblock");
if (logblock.hasPermission(sender, "logblock.me"))
sender.sendMessage(ChatColor.GOLD + "logblock.me");
if (logblock.hasPermission(sender, "logblock.tp"))
sender.sendMessage(ChatColor.GOLD + "logblock.tp");
if (logblock.hasPermission(sender, "logblock.rollback"))
sender.sendMessage(ChatColor.GOLD + "logblock.rollback");
if (logblock.hasPermission(sender, "logblock.hide"))
sender.sendMessage(ChatColor.GOLD + "logblock.hide");
} else if (command.equals("tool")) {
if (sender instanceof Player) {
final Player player = (Player)sender;
if (args.length == 1) {
if (logblock.hasPermission(player, "logblock.tool"))
BukkitUtils.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")) {
logblock.getSession(player.getName()).toolEnabled = true;
player.sendMessage(ChatColor.GREEN + "Tool enabled.");
} else if (args[1].equalsIgnoreCase("disable") || args[1].equalsIgnoreCase("off")) {
logblock.getSession(player.getName()).toolEnabled = false;
player.sendMessage(ChatColor.GREEN + "Tool disabled.");
} else if (logblock.hasPermission(player, "logblock.lookup"))
try {
final QueryParams params = new QueryParams(logblock, sender, ArgsToList(args, 1));
logblock.getSession(player.getName()).toolQuery = params;
sender.sendMessage(ChatColor.GREEN + "Set tool query to: " + params.getTitle());
} catch (final Exception ex) {
sender.sendMessage(ChatColor.RED + ex.getMessage());
}
else else
sender.sendMessage(ChatColor.GREEN + "You aren't hided anylonger."); sender.sendMessage(ChatColor.RED + "You aren't allowed to do this.");
} else } else
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); sender.sendMessage(ChatColor.RED + "You have to be a player.");
} else } else if (command.equals("toolblock")) {
sender.sendMessage(ChatColor.RED + "You have to be a player."); if (sender instanceof Player) {
} else if (args[0].equalsIgnoreCase("savequeue")) { final Player player = (Player)sender;
if (logblock.checkPermission(sender, "logblock.rollback")) if (args.length == 1) {
try { if (logblock.hasPermission(player, "logblock.toolblock"))
new Thread(new CommandSaveQueue(sender, null)).run(); BukkitUtils.giveTool(player, config.toolblockID);
} catch (Exception ex) { else
sender.sendMessage(ex.getMessage()); player.sendMessage(ChatColor.RED + "You aren't allowed to do this.");
} } else if (args[1].equalsIgnoreCase("enable") || args[1].equalsIgnoreCase("on")) {
else logblock.getSession(player.getName()).toolBlockEnabled = true;
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); player.sendMessage(ChatColor.GREEN + "Tool block enabled.");
} else if (args[0].equalsIgnoreCase("rollback") || args[0].equalsIgnoreCase("undo")) { } else if (args[1].equalsIgnoreCase("disable") || args[1].equalsIgnoreCase("off")) {
if (logblock.checkPermission(sender, "logblock.rollback")) { logblock.getSession(player.getName()).toolBlockEnabled = false;
try { player.sendMessage(ChatColor.GREEN + "Tool block disabled.");
final List<String> argsList = Arrays.asList(args); } else if (logblock.hasPermission(player, "logblock.lookup"))
argsList.remove(1); try {
final QueryParams params = new QueryParams(logblock); final QueryParams params = new QueryParams(logblock, sender, ArgsToList(args, 1));
params.parseArgs(sender, argsList); logblock.getSession(player.getName()).toolBlockQuery = params;
params.setLimit(-1); sender.sendMessage(ChatColor.GREEN + "Set tool block query to: " + params.getTitle());
params.setOrder(QueryParams.Order.DESC); } catch (final Exception ex) {
params.setSummarizationMode(QueryParams.SummarizationMode.NONE); sender.sendMessage(ChatColor.RED + ex.getMessage());
new Thread(new CommandRollback(sender, params)).run(); }
} catch (final Exception ex) { else
sender.sendMessage(ex.getMessage()); sender.sendMessage(ChatColor.RED + "You aren't allowed to do this.");
}
} else
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this.");
} else if (args[0].equalsIgnoreCase("redo")) {
if (logblock.checkPermission(sender, "logblock.rollback")) {
try {
final List<String> argsList = Arrays.asList(args);
argsList.remove(1);
final QueryParams params = new QueryParams(logblock);
params.parseArgs(sender, argsList);
params.setLimit(-1);
params.setOrder(QueryParams.Order.ASC);
params.setSummarizationMode(QueryParams.SummarizationMode.NONE);
new Thread(new CommandRedo(sender, params)).run();
} catch (final Exception ex) {
sender.sendMessage(ex.getMessage());
}
} else
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this.");
} else if (args[0].equalsIgnoreCase("me")) {
if (sender instanceof Player) {
if (logblock.checkPermission(sender, "logblock.rollback")) {
final QueryParams params = new QueryParams(logblock);
params.setPlayer(((Player)sender).getName());
params.setSummarizationMode(SummarizationMode.TYPES);
} else } else
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this."); sender.sendMessage(ChatColor.RED + "You have to be a player.");
} else } else if (command.equals("hide")) {
sender.sendMessage(ChatColor.RED + "You have to be a player."); if (sender instanceof Player) {
} else if (args[0].equalsIgnoreCase("writelogfile")) { if (logblock.hasPermission(sender, "logblock.hide")) {
if (logblock.checkPermission(sender,"logblock.rollback")) { if (logblock.getConsumer().hide((Player)sender))
try { sender.sendMessage(ChatColor.GREEN + "You are now hided and won't appear in any log. Type '/lb hide' again to unhide");
final List<String> argsList = Arrays.asList(args); else
argsList.remove(1); sender.sendMessage(ChatColor.GREEN + "You aren't hided anylonger.");
final QueryParams params = new QueryParams(logblock); } else
params.parseArgs(sender, argsList); sender.sendMessage(ChatColor.RED + "You aren't allowed to do this.");
params.setLimit(-1); } else
params.setBlockChangeType(BlockChangeType.ALL); sender.sendMessage(ChatColor.RED + "You have to be a player.");
params.setSummarizationMode(SummarizationMode.NONE); } else if (args[0].equalsIgnoreCase("savequeue")) {
new Thread(new CommandWriteLogFile(sender, params)).run(); if (logblock.hasPermission(sender, "logblock.rollback"))
} catch (final Exception ex) {
sender.sendMessage(ex.getMessage());
}
} else
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this");
} else if (args[0].equalsIgnoreCase("tp")) {
if (sender instanceof Player) {
if (logblock.checkPermission(sender,"logblock.tp")) {
try { try {
final List<String> argsList = Arrays.asList(args); new CommandSaveQueue(sender, null);
argsList.remove(1);
final QueryParams params = new QueryParams(logblock);
params.parseArgs(sender, argsList);
params.setLimit(1);
new Thread(new CommandTeleport(sender, null)).run();
} catch (final Exception ex) { } catch (final Exception ex) {
sender.sendMessage(ex.getMessage()); sender.sendMessage(ChatColor.RED + ex.getMessage());
} }
else
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this.");
} else if (command.equals("rollback") || command.equals("undo") || command.equals("rb")) {
if (logblock.hasPermission(sender, "logblock.rollback"))
try {
final QueryParams params = new QueryParams(logblock);
params.minutes = logblock.getConfig().defaultTime;
params.parseArgs(sender, ArgsToList(args, 1));
params.limit = -1;
params.order = Order.DESC;
params.sum = SummarizationMode.NONE;
params.bct = BlockChangeType.ALL;
params.selectFullBlockData = true;
new CommandRollback(sender, params);
} catch (final Exception ex) {
sender.sendMessage(ChatColor.RED + ex.getMessage());
}
else
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this.");
} else if (command.equals("redo")) {
if (logblock.hasPermission(sender, "logblock.rollback"))
try {
final QueryParams params = new QueryParams(logblock);
params.minutes = logblock.getConfig().defaultTime;
params.parseArgs(sender, ArgsToList(args, 1));
params.limit = -1;
params.order = Order.ASC;
params.sum = SummarizationMode.NONE;
params.bct = BlockChangeType.ALL;
params.selectFullBlockData = true;
new CommandRedo(sender, params);
} catch (final Exception ex) {
sender.sendMessage(ChatColor.RED + ex.getMessage());
}
else
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this.");
} else if (command.equals("me")) {
if (sender instanceof Player) {
if (logblock.hasPermission(sender, "logblock.me"))
try {
final Player player = (Player)sender;
final QueryParams params = new QueryParams(logblock);
params.setPlayer(player.getName());
params.sum = SummarizationMode.TYPES;
params.world = player.getWorld();
new CommandLookup(sender, params);
} catch (final Exception ex) {
sender.sendMessage(ChatColor.RED + ex.getMessage());
}
else
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this.");
} else } else
sender.sendMessage(ChatColor.RED + "You have to be a player.");
} else if (command.equals("writelogfile")) {
if (logblock.hasPermission(sender, "logblock.rollback"))
try {
final QueryParams params = new QueryParams(logblock, sender, ArgsToList(args, 1));
params.limit = -1;
params.bct = BlockChangeType.ALL;
params.sum = SummarizationMode.NONE;
new CommandWriteLogFile(sender, params);
} catch (final Exception ex) {
sender.sendMessage(ChatColor.RED + ex.getMessage());
}
else
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this");
} else if (command.equals("clearlog")) {
if (logblock.hasPermission(sender, "logblock.clearlog"))
try {
final QueryParams params = new QueryParams(logblock, sender, ArgsToList(args, 1));
params.bct = BlockChangeType.ALL;
params.limit = -1;
new CommandClearLog(sender, params);
} catch (final Exception ex) {
sender.sendMessage(ChatColor.RED + ex.getMessage());
}
else
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this");
} else if (command.equals("tp")) {
if (sender instanceof Player) {
if (logblock.hasPermission(sender, "logblock.tp"))
try {
new CommandTeleport(sender, new QueryParams(logblock, sender, ArgsToList(args, 1)));
} catch (final Exception ex) {
sender.sendMessage(ChatColor.RED + ex.getMessage());
}
else
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this");
} else
sender.sendMessage(ChatColor.RED + "You have to be a player.");
} else if (command.equals("lookup") || QueryParams.isKeyWord(args[0])) {
if (logblock.hasPermission(sender, "logblock.lookup"))
try {
final List<String> argsList = new ArrayList<String>(Arrays.asList(args));
if (command.equals("lookup"))
argsList.remove(0);
new CommandLookup(sender, new QueryParams(logblock, sender, argsList));
} catch (final Exception ex) {
sender.sendMessage(ChatColor.RED + ex.getMessage());
}
else
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this"); sender.sendMessage(ChatColor.RED + "You aren't allowed to do this");
} else } else
sender.sendMessage(ChatColor.RED + "You have to be a player."); sender.sendMessage(ChatColor.RED + "Unknown command '" + args[0] + "'");
} else if (QueryParams.isKeyWord(args[0])) {
try {
final QueryParams params = new QueryParams(logblock);
params.parseArgs(sender, Arrays.asList(args));
new Thread(new CommandLookup(sender, params)).run();
} catch (final Exception ex) {
log.log(Level.SEVERE, "Error at Command", ex);
sender.sendMessage(ex.getMessage());
}
} }
return true; return true;
} }
private abstract class LBCommand implements Runnable public abstract class LBCommand implements Runnable, Closeable
{ {
protected final CommandSender sender; protected final CommandSender sender;
protected final QueryParams params; protected final QueryParams params;
@@ -196,20 +291,14 @@ public class CommandsHandler implements CommandExecutor
LBCommand(CommandSender sender, QueryParams params) throws Exception { LBCommand(CommandSender sender, QueryParams params) throws Exception {
this.sender = sender; this.sender = sender;
this.params = params; this.params = params;
try { conn = logblock.getConnection();
conn = logblock.getConnection(); state = conn.createStatement();
conn.setAutoCommit(false); if (scheduler.scheduleAsyncDelayedTask(logblock, this) == -1)
state = conn.createStatement(); throw new Exception("Failed to schedule the command");
log.info("Query: " + params.getQuery());
rs = state.executeQuery(params.getQuery());
} catch (SQLException ex) {
close();
log.log(Level.SEVERE, "[LogBlock CommandsHandler] Error while executing query", ex);
throw new Exception("Error while executing query");
}
} }
protected void close() { @Override
public final void close() {
try { try {
if (conn != null) if (conn != null)
conn.close(); conn.close();
@@ -223,7 +312,7 @@ public class CommandsHandler implements CommandExecutor
} }
} }
private class CommandLookup extends LBCommand public class CommandLookup extends LBCommand
{ {
CommandLookup(CommandSender sender, QueryParams params) throws Exception { CommandLookup(CommandSender sender, QueryParams params) throws Exception {
super(sender, params); super(sender, params);
@@ -232,15 +321,16 @@ public class CommandsHandler implements CommandExecutor
@Override @Override
public void run() { public void run() {
try { try {
final SummarizationMode sum = params.getSummarizationMode(); rs = state.executeQuery(params.getQuery());
final HistoryFormatter histformatter = new HistoryFormatter(sum);
sender.sendMessage(ChatColor.DARK_AQUA + params.getTitle()); sender.sendMessage(ChatColor.DARK_AQUA + params.getTitle());
if (rs.next()) { if (rs.next()) {
rs.beforeFirst(); rs.beforeFirst();
final SummarizationMode sum = params.sum;
final HistoryFormatter histformatter = new HistoryFormatter(sum);
if (sum == SummarizationMode.TYPES) if (sum == SummarizationMode.TYPES)
sender.sendMessage(ChatColor.GOLD + String.format("%-6s %-6s %s", "Creat", "Destr", "Block")); sender.sendMessage(ChatColor.GOLD + String.format("%-6s %-6s %s", "Creat", "Destr", "Block"));
else if (sum == SummarizationMode.PLAYERS) else if (sum == SummarizationMode.PLAYERS)
sender.sendMessage(ChatColor.GOLD + String.format("%-6d %-6d %s", rs.getInt("created"), rs.getInt("destroyed"), rs.getString("playername"))); sender.sendMessage(ChatColor.GOLD + String.format("%-6s %-6s %s", "Created", "Destroyed", "Playername"));
while (rs.next()) while (rs.next())
sender.sendMessage(ChatColor.GOLD + histformatter.format(rs)); sender.sendMessage(ChatColor.GOLD + histformatter.format(rs));
} else } else
@@ -254,7 +344,7 @@ public class CommandsHandler implements CommandExecutor
} }
} }
private class CommandWriteLogFile extends LBCommand public class CommandWriteLogFile extends LBCommand
{ {
CommandWriteLogFile(CommandSender sender, QueryParams params) throws Exception { CommandWriteLogFile(CommandSender sender, QueryParams params) throws Exception {
super(sender, params); super(sender, params);
@@ -263,15 +353,16 @@ public class CommandsHandler implements CommandExecutor
@Override @Override
public void run() { public void run() {
try { try {
final File file = new File ("plugins/LogBlock/log/" + params.getTitle() + ".log"); rs = state.executeQuery(params.getQuery());
final File file = new File("plugins/LogBlock/log/" + params.getTitle() + ".log");
file.createNewFile();
final FileWriter writer = new FileWriter(file); final FileWriter writer = new FileWriter(file);
final String newline = System.getProperty("line.separator"); final String newline = System.getProperty("line.separator");
final HistoryFormatter histformatter = new HistoryFormatter(params.getSummarizationMode()); final HistoryFormatter histformatter = new HistoryFormatter(params.sum);
file.getParentFile().mkdirs(); file.getParentFile().mkdirs();
sender.sendMessage(ChatColor.GREEN + "Creating " + file.getName()); sender.sendMessage(ChatColor.GREEN + "Creating " + file.getName());
while (rs.next()) { while (rs.next())
writer.write(histformatter.format(rs) + newline); writer.write(histformatter.format(rs) + newline);
}
writer.close(); writer.close();
sender.sendMessage(ChatColor.GREEN + "Done"); sender.sendMessage(ChatColor.GREEN + "Done");
} catch (final SQLException ex) { } catch (final SQLException ex) {
@@ -286,7 +377,7 @@ public class CommandsHandler implements CommandExecutor
} }
} }
private class CommandSaveQueue extends LBCommand public class CommandSaveQueue extends LBCommand
{ {
CommandSaveQueue(CommandSender sender, QueryParams params) throws Exception { CommandSaveQueue(CommandSender sender, QueryParams params) throws Exception {
super(sender, params); super(sender, params);
@@ -296,14 +387,13 @@ public class CommandsHandler implements CommandExecutor
public void run() { public void run() {
final Consumer consumer = logblock.getConsumer(); final Consumer consumer = logblock.getConsumer();
sender.sendMessage(ChatColor.DARK_AQUA + "Current queue size: " + consumer.getQueueSize()); sender.sendMessage(ChatColor.DARK_AQUA + "Current queue size: " + consumer.getQueueSize());
while (consumer.getQueueSize() > 0) { while (consumer.getQueueSize() > 0)
consumer.run(); consumer.run();
}
sender.sendMessage(ChatColor.GREEN + "Queue saved successfully"); sender.sendMessage(ChatColor.GREEN + "Queue saved successfully");
} }
} }
private class CommandTeleport extends LBCommand public class CommandTeleport extends LBCommand
{ {
CommandTeleport(CommandSender sender, QueryParams params) throws Exception { CommandTeleport(CommandSender sender, QueryParams params) throws Exception {
super(sender, params); super(sender, params);
@@ -312,21 +402,24 @@ public class CommandsHandler implements CommandExecutor
@Override @Override
public void run() { public void run() {
try { try {
rs = state.executeQuery("SELECT x, z FROM `" + params.getTable() + "` INNER JOIN `lb-players` USING (playerid) " + params.getWhere() + params.getOrderBy() + " LIMIT 1");
if (rs.next()) { if (rs.next()) {
final Player player = (Player)sender; final Player player = (Player)sender;
player.teleport(new Location(params.getWorld(), rs.getInt("x"), rs.getInt("y"), rs.getInt("z"))); final int x = rs.getInt("x");
final int z = rs.getInt("z");
player.teleport(new Location(params.world, x + 0.5, player.getWorld().getHighestBlockYAt(x, z), z + 0.5, player.getLocation().getYaw(), 90));
} else } else
sender.sendMessage(ChatColor.RED + "Query returned no result"); sender.sendMessage(ChatColor.RED + "Query returned no result");
} catch (final SQLException ex) { } catch (final SQLException ex) {
sender.sendMessage(ChatColor.RED + "SQL exception"); sender.sendMessage(ChatColor.RED + "SQL exception");
log.log(Level.SEVERE, "[LogBlock WriteLogFile] SQL exception", ex); log.log(Level.SEVERE, "[LogBlock Teleport] SQL exception", ex);
} finally { } finally {
close(); close();
} }
} }
} }
private class CommandRollback extends LBCommand public class CommandRollback extends LBCommand
{ {
CommandRollback(CommandSender sender, QueryParams params) throws Exception { CommandRollback(CommandSender sender, QueryParams params) throws Exception {
super(sender, params); super(sender, params);
@@ -335,38 +428,38 @@ public class CommandsHandler implements CommandExecutor
@Override @Override
public void run() { public void run() {
try { try {
final WorldEditor editor = new WorldEditor(logblock, this, params.getWorld()); rs = state.executeQuery(params.getQuery());
while (rs.next()) { sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":");
editor.queueBlockChange(rs.getInt("type"), rs.getInt("replaced"), rs.getByte("data"), rs.getInt("x"), rs.getInt("y"), rs.getInt("z")); 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(); final int changes = editor.getSize();
sender.sendMessage(ChatColor.GREEN + "" + changes + " Changes found."); sender.sendMessage(ChatColor.GREEN.toString() + changes + " blocks found.");
final long start = System.currentTimeMillis(); if (config.askRollbacks && questioner != null && sender instanceof Player && !questioner.askQuestion((Player)sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) {
if (!editor.start()) { sender.sendMessage(ChatColor.RED + "Rollback aborted");
sender.sendMessage(ChatColor.RED + "Failed to schedule rollback task");
return; return;
} }
synchronized (this) { final long start = System.currentTimeMillis();
try { editor.start();
this.wait();
} catch (final InterruptedException e) {
sender.sendMessage(ChatColor.RED + "Rollback Interrupted");
log.severe("[LogBlock Rollback] Interrupted");
}
}
sender.sendMessage(ChatColor.GREEN + "Rollback finished successfully"); 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 + "Undid " + editor.getSuccesses() + " of " + changes + " changes (" + editor.getErrors() + " errors, " + editor.getBlacklistCollisions() + " blacklist collisions)");
sender.sendMessage(ChatColor.GREEN + "Took: " + (System.currentTimeMillis() - start) + "ms"); sender.sendMessage(ChatColor.GREEN + "Took: " + (System.currentTimeMillis() - start) + "ms");
} catch (final SQLException ex) { } catch (final SQLException ex) {
sender.sendMessage(ChatColor.RED + "SQL exception"); sender.sendMessage(ChatColor.RED + "SQL exception");
log.log(Level.SEVERE, "[LogBlock Rollback] SQL exception", ex); log.log(Level.SEVERE, "[LogBlock Rollback] SQL exception", ex);
} catch (final QuestionerException ex) {
sender.sendMessage(ChatColor.RED + "Questioner exception");
log.log(Level.SEVERE, "[LogBlock Rollback] Questioner exception", ex);
} catch (final WorldEditorException ex) {
sender.sendMessage(ChatColor.RED + "WorldEditor exception");
log.log(Level.SEVERE, "[LogBlock Rollback] WorldEditor exception", ex);
} finally { } finally {
close(); close();
} }
} }
} }
private class CommandRedo extends LBCommand public class CommandRedo extends LBCommand
{ {
CommandRedo(CommandSender sender, QueryParams params) throws Exception { CommandRedo(CommandSender sender, QueryParams params) throws Exception {
super(sender, params); super(sender, params);
@@ -375,39 +468,105 @@ public class CommandsHandler implements CommandExecutor
@Override @Override
public void run() { public void run() {
try { try {
final WorldEditor editor = new WorldEditor(logblock, this, params.getWorld()); rs = state.executeQuery(params.getQuery());
while (rs.next()) { sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":");
editor.queueBlockChange(rs.getInt("replaced"), rs.getInt("type"), rs.getByte("data"), rs.getInt("x"), rs.getInt("y"), rs.getInt("z")); final WorldEditor editor = new WorldEditor(logblock, params.world);
} 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(); final int changes = editor.getSize();
sender.sendMessage(ChatColor.GREEN + "" + changes + " Changes found."); sender.sendMessage(ChatColor.GREEN.toString() + changes + " blocks found.");
final long start = System.currentTimeMillis(); if (config.askRedos && questioner != null && sender instanceof Player && !questioner.askQuestion((Player)sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) {
if (!editor.start()) { sender.sendMessage(ChatColor.RED + "Redo aborted");
sender.sendMessage(ChatColor.RED + "Failed to schedule redo task");
return; return;
} }
synchronized (this) { final long start = System.currentTimeMillis();
try { editor.start();
this.wait();
} catch (final InterruptedException e) {
sender.sendMessage(ChatColor.RED + "Redo Interrupted");
log.severe("[LogBlock Redo] Interrupted");
}
}
sender.sendMessage(ChatColor.GREEN + "Redo finished successfully"); sender.sendMessage(ChatColor.GREEN + "Redo finished successfully");
sender.sendMessage(ChatColor.GREEN + "Redid " + editor.getSuccesses() + " of " + changes + " changes (" + editor.getErrors() + " errors, " + editor.getBlacklistCollisions() + " blacklist collisions)"); sender.sendMessage(ChatColor.GREEN + "Redid " + editor.getSuccesses() + " of " + changes + " changes (" + editor.getErrors() + " errors, " + editor.getBlacklistCollisions() + " blacklist collisions)");
sender.sendMessage(ChatColor.GREEN + "Took: " + (System.currentTimeMillis() - start) + "ms"); sender.sendMessage(ChatColor.GREEN + "Took: " + (System.currentTimeMillis() - start) + "ms");
} catch (final SQLException ex) { } catch (final SQLException ex) {
sender.sendMessage(ChatColor.RED + "SQL exception"); sender.sendMessage(ChatColor.RED + "SQL exception");
log.log(Level.SEVERE, "[LogBlock Redo] SQL exception", ex); log.log(Level.SEVERE, "[LogBlock Redo] SQL exception", ex);
} catch (final QuestionerException ex) {
sender.sendMessage(ChatColor.RED + "Questioner exception");
log.log(Level.SEVERE, "[LogBlock Redo] Questioner exception", ex);
} catch (final WorldEditorException ex) {
sender.sendMessage(ChatColor.RED + "WorldEditor exception");
log.log(Level.SEVERE, "[LogBlock Redo] WorldEditor exception", ex);
} finally { } finally {
close(); close();
} }
} }
} }
private String getMaterialName(int type) { public class CommandClearLog extends LBCommand
return Material.getMaterial(type).toString().toLowerCase().replace('_', ' '); {
CommandClearLog(CommandSender sender, QueryParams params) throws Exception {
super(sender, params);
}
@Override
public void run() {
try {
final File dumpFolder = new File(logblock.getDataFolder(), "dumb");
int deleted;
for (final String table : config.tables.values()) {
rs = state.executeQuery("SELECT count(*) FROM `" + table + "` " + params.getWhere());
rs.next();
if ((deleted = rs.getInt(1)) > 0) {
if (config.askClearLogs && sender instanceof Player && questioner != null) {
sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":");
sender.sendMessage(ChatColor.GREEN.toString() + deleted + " blocks found.");
if (!questioner.askQuestion((Player)sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) {
sender.sendMessage(ChatColor.RED + "ClearLog aborted");
return;
}
}
if (config.dumpDeletedLog)
try {
state.execute("SELECT * FROM `" + table + "` " + params.getWhere() + "INTO OUTFILE '" + new File(dumpFolder, 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());
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");
rs.next();
if ((deleted = rs.getInt(1)) > 0) {
if (config.dumpDeletedLog)
state.execute("SELECT id, signtext FROM `" + table + "-sign` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, table + "-sign " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'");
state.execute("DELETE `" + table + "-sign` FROM `" + table + "-sign` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL;");
sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-sign. Deleted " + deleted + " entries.");
}
rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-chest` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL");
rs.next();
if ((deleted = rs.getInt(1)) > 0) {
if (config.dumpDeletedLog)
state.execute("SELECT id, itemtype, itemamount, itemdata, FROM `" + table + "-chest` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, table + "-chest " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'");
state.execute("DELETE `" + table + "-chest` FROM `" + table + "-chest` LEFT JOIN `" + table + "` USING (id) WHERE `" + table + "`.id IS NULL;");
sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-chest. Deleted " + deleted + " entries.");
}
}
} catch (final SQLException ex) {
sender.sendMessage(ChatColor.RED + "SQL exception");
log.log(Level.SEVERE, "[LogBlock ClearLog] SQL exception", ex);
} catch (final QuestionerException ex) {
sender.sendMessage(ChatColor.RED + "Questioner exception");
log.log(Level.SEVERE, "[LogBlock ClearLog] Questioner exception", ex);
} finally {
close();
}
}
}
private List<String> ArgsToList(String[] arr, int offset) {
final List<String> list = new ArrayList<String>(Arrays.asList(arr));
for (int i = 0; i < offset; i++)
list.remove(0);
return list;
} }
private class HistoryFormatter private class HistoryFormatter
@@ -422,50 +581,56 @@ public class CommandsHandler implements CommandExecutor
String format(ResultSet rs) { String format(ResultSet rs) {
try { try {
if (sum == SummarizationMode.NONE) { if (sum == SummarizationMode.NONE) {
final StringBuffer msg = new StringBuffer(formatter.format(rs.getTimestamp("date")) + " " + rs.getString("playername") + " "); final StringBuilder msg = new StringBuilder(formatter.format(rs.getTimestamp("date")) + " " + rs.getString("playername") + " ");
final int type = rs.getInt("type"); final int type = rs.getInt("type");
final int replaced = rs.getInt("replaced"); final int replaced = rs.getInt("replaced");
if ((type == 63 || type == 68) && rs.getString("signtext") != null) final String signtext;
msg.append("created " + rs.getString("signtext")); if ((type == 63 || type == 68 || replaced == 63 || replaced == 68) && (signtext = rs.getString("signtext")) != null) {
else if (type == replaced) { final String action;
if (type == 23 || type == 54 || type == 61) if (type == 0)
msg.append("looked inside " + getMaterialName(type)); 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) } else if (type == 0)
msg.append("destroyed " + getMaterialName(replaced)); msg.append("destroyed " + BukkitUtils.getMaterialName(replaced));
else if (replaced == 0) else if (replaced == 0)
msg.append("created " + getMaterialName(type)); msg.append("created " + BukkitUtils.getMaterialName(type));
else else
msg.append("replaced " + getMaterialName(replaced) + " with " + getMaterialName(type)); msg.append("replaced " + BukkitUtils.getMaterialName(replaced) + " with " + BukkitUtils.getMaterialName(type));
return msg.toString(); return msg.toString();
} else if (sum == SummarizationMode.TYPES) } else if (sum == SummarizationMode.TYPES)
return fillWithSpaces(rs.getInt("created")) + fillWithSpaces(rs.getInt("destroyed")) + Material.getMaterial(rs.getInt("type")).toString().toLowerCase().replace('_', ' '); return fillWithSpaces(rs.getInt("created")) + fillWithSpaces(rs.getInt("destroyed")) + BukkitUtils.getMaterialName(rs.getInt("type"));
else else
return fillWithSpaces(rs.getInt("created")) + fillWithSpaces(rs.getInt("destroyed")) + rs.getString("playername"); return fillWithSpaces(rs.getInt("created")) + fillWithSpaces(rs.getInt("destroyed")) + rs.getString("playername");
} catch (final Exception ex) { } catch (final Exception ex) {
log.log(Level.SEVERE, "[LogBlock HistoryFormatter] Error", ex);
return null; return null;
} }
} }
private String fillWithSpaces(Integer number) { private String fillWithSpaces(Integer number) {
final StringBuffer filled = new StringBuffer(number.toString()); final StringBuilder filled = new StringBuilder(number.toString());
final int neededSpaces = (36 - filled.length() * 6) / 4; final int neededSpaces = (36 - filled.length() * 6) / 4;
for (int i = 0; i < neededSpaces; i++) for (int i = 0; i < neededSpaces; i++)
filled.append(' ');; filled.append(' ');
return filled.toString(); return filled.toString();
}
}
private void giveTool(Player player, int tool) {
if (player.getInventory().contains(config.toolID))
player.sendMessage(ChatColor.RED + "You have alredy a tool");
else {
final int free = player.getInventory().firstEmpty();
if (free >= 0) {
player.getInventory().setItem(free, player.getItemInHand());
player.setItemInHand(new ItemStack(config.toolID, 1));
player.sendMessage(ChatColor.GREEN + "Here is your tool.");
} else
player.sendMessage(ChatColor.RED + "You have no empty slot in your inventory");
} }
} }
} }

View File

@@ -6,19 +6,20 @@ import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.util.config.Configuration; import org.bukkit.util.config.Configuration;
import de.diddiz.util.Utils;
public class Config { public class Config
{
public final HashMap<Integer, String> tables; public final HashMap<Integer, String> tables;
public final String url; public final String url;
public final String user; public final String user;
public final String password; public final String password;
public final int delayBetweenRuns; public final int delayBetweenRuns;
public final int minCountPerRun; public final int forceToProcessAtLeast;
public final int maxCountPerRun; public final int timePerRun;
public final int maxTimePerRun;
public final boolean useBukkitScheduler; public final boolean useBukkitScheduler;
public final int keepLogDays; public final int keepLogDays;
public final boolean dumpDeletedLog; public final boolean dumpDeletedLog;
@@ -26,6 +27,7 @@ public class Config {
public final boolean logBlockDestroyings; public final boolean logBlockDestroyings;
public final boolean logSignTexts; public final boolean logSignTexts;
public final boolean logExplosions; public final boolean logExplosions;
public final boolean logCreeperExplosionsAsPlayerWhoTriggeredThese;
public final boolean logFire; public final boolean logFire;
public final boolean logLeavesDecay; public final boolean logLeavesDecay;
public final boolean logLavaFlow; public final boolean logLavaFlow;
@@ -34,16 +36,21 @@ public class Config {
public final LogKillsLevel logKillsLevel; public final LogKillsLevel logKillsLevel;
public final Set<Integer> dontRollback; public final Set<Integer> dontRollback;
public final Set<Integer> replaceAnyway; public final Set<Integer> replaceAnyway;
public final QueryParams toolQuery;
public final QueryParams toolBlockQuery;
public final int defaultDist; public final int defaultDist;
public final int defaultTime; public final int defaultTime;
public final int toolID; public final int toolID;
public final int toolblockID; public final int toolblockID;
public final boolean askRollbacks;
public final boolean askRedos;
public final boolean askClearLogs;
enum LogKillsLevel { public static enum LogKillsLevel {
PLAYERS, MONSTERS, ANIMALS PLAYERS, MONSTERS, ANIMALS
} }
Config (LogBlock logblock) throws Exception { Config(LogBlock logblock) throws Exception {
final Configuration config = logblock.getConfiguration(); final Configuration config = logblock.getConfiguration();
config.load(); config.load();
final List<String> keys = config.getKeys(null); final List<String> keys = config.getKeys(null);
@@ -70,19 +77,12 @@ public class Config {
subkeys = config.getKeys("consumer"); subkeys = config.getKeys("consumer");
if (subkeys == null) if (subkeys == null)
subkeys = new ArrayList<String>(); subkeys = new ArrayList<String>();
if (!subkeys.contains("delayBetweenRuns")) { if (!subkeys.contains("delayBetweenRuns"))
if (subkeys.contains("delay")) { config.setProperty("consumer.delayBetweenRuns", 6);
config.setProperty("consumer.delayBetweenRuns", config.getInt("consumer.delay", 6)); if (!subkeys.contains("forceToProcessAtLeast"))
config.removeProperty("consumer.delay"); config.setProperty("consumer.forceToProcessAtLeast", 0);
} else if (!subkeys.contains("timePerRun"))
config.setProperty("consumer.delayBetweenRuns", 6); config.setProperty("consumer.timePerRun", 100);
}
if (!subkeys.contains("minCountPerRun"))
config.setProperty("consumer.minCountPerRun", 100);
if (!subkeys.contains("maxCountPerRun"))
config.setProperty("consumer.maxCountPerRun", 1000);
if (!subkeys.contains("maxTimePerRun"))
config.setProperty("consumer.maxTimePerRun", 100);
if (!subkeys.contains("useBukkitScheduler")) if (!subkeys.contains("useBukkitScheduler"))
config.setProperty("consumer.useBukkitScheduler", true); config.setProperty("consumer.useBukkitScheduler", true);
subkeys = config.getKeys("clearlog"); subkeys = config.getKeys("clearlog");
@@ -103,6 +103,8 @@ public class Config {
config.setProperty("logging.logSignTexts", false); config.setProperty("logging.logSignTexts", false);
if (!subkeys.contains("logExplosions")) if (!subkeys.contains("logExplosions"))
config.setProperty("logging.logExplosions", false); config.setProperty("logging.logExplosions", false);
if (!subkeys.contains("logCreeperExplosionsAsPlayerWhoTriggeredThese"))
config.setProperty("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false);
if (!subkeys.contains("logFire")) if (!subkeys.contains("logFire"))
config.setProperty("logging.logFire", false); config.setProperty("logging.logFire", false);
if (!subkeys.contains("logLeavesDecay")) if (!subkeys.contains("logLeavesDecay"))
@@ -133,24 +135,37 @@ public class Config {
config.setProperty("lookup.toolID", 270); config.setProperty("lookup.toolID", 270);
if (!subkeys.contains("toolblockID")) if (!subkeys.contains("toolblockID"))
config.setProperty("lookup.toolblockID", 7); config.setProperty("lookup.toolblockID", 7);
if (!subkeys.contains("toolQuery"))
config.setProperty("lookup.toolQuery", "area 0 all sum none limit 15 desc");
if (!subkeys.contains("toolBlockQuery"))
config.setProperty("lookup.toolBlockQuery", "area 0 all sum none limit 15 desc");
subkeys = config.getKeys("questioner");
if (subkeys == null)
subkeys = new ArrayList<String>();
if (!subkeys.contains("askRollbacks"))
config.setProperty("questioner.askRollbacks", true);
if (!subkeys.contains("askRedos"))
config.setProperty("questioner.askRedos", true);
if (!subkeys.contains("askClearLogs"))
config.setProperty("questioner.askClearLogs", true);
if (!config.save()) if (!config.save())
throw new Exception("Error while writing to config.yml"); throw new Exception("Error while writing to config.yml");
url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getString("mysql.port") + "/" + config.getString("mysql.database"); url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getString("mysql.port") + "/" + config.getString("mysql.database");
user = config.getString("mysql.user"); user = config.getString("mysql.user");
password = config.getString("mysql.password"); password = config.getString("mysql.password");
delayBetweenRuns = config.getInt("consumer.delayBetweenRuns", 6); delayBetweenRuns = config.getInt("consumer.delayBetweenRuns", 6);
minCountPerRun = config.getInt("consumer.minCountPerRun", 100); forceToProcessAtLeast = config.getInt("consumer.forceToProcessAtLeast", 0);
maxCountPerRun = config.getInt("consumer.maxCountPerRun", 1000); timePerRun = config.getInt("consumer.timePerRun", 100);
maxTimePerRun = config.getInt("consumer.maxTimePerRun", 100);
useBukkitScheduler = config.getBoolean("consumer.useBukkitScheduler", true); useBukkitScheduler = config.getBoolean("consumer.useBukkitScheduler", true);
keepLogDays = config.getInt("clearlog.keepLogDays", -1); keepLogDays = config.getInt("clearlog.keepLogDays", -1);
if (keepLogDays*86400000L > System.currentTimeMillis()) if (keepLogDays * 86400000L > System.currentTimeMillis())
throw new Exception("Too large timespan for keepLogDays. Must be shorter than " + (int)(System.currentTimeMillis()/86400000L) + " days."); throw new Exception("Too large timespan for keepLogDays. Must be shorter than " + (int)(System.currentTimeMillis() / 86400000L) + " days.");
dumpDeletedLog = config.getBoolean("clearlog.dumpDeletedLog", true); dumpDeletedLog = config.getBoolean("clearlog.dumpDeletedLog", true);
logBlockCreations = config.getBoolean("logging.logBlockCreations", true); logBlockCreations = config.getBoolean("logging.logBlockCreations", true);
logBlockDestroyings = config.getBoolean("logging.logBlockDestroyings", true); logBlockDestroyings = config.getBoolean("logging.logBlockDestroyings", true);
logSignTexts = config.getBoolean("logging.logSignTexts", false); logSignTexts = config.getBoolean("logging.logSignTexts", false);
logExplosions = config.getBoolean("logging.logExplosions", false); logExplosions = config.getBoolean("logging.logExplosions", false);
logCreeperExplosionsAsPlayerWhoTriggeredThese = config.getBoolean("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false);
logFire = config.getBoolean("logging.logFire", false); logFire = config.getBoolean("logging.logFire", false);
logChestAccess = config.getBoolean("logging.logChestAccess", false); logChestAccess = config.getBoolean("logging.logChestAccess", false);
logLeavesDecay = config.getBoolean("logging.logLeavesDecay", false); logLeavesDecay = config.getBoolean("logging.logLeavesDecay", false);
@@ -163,21 +178,37 @@ public class Config {
} }
dontRollback = new HashSet<Integer>(config.getIntList("rollback.dontRollback", null)); dontRollback = new HashSet<Integer>(config.getIntList("rollback.dontRollback", null));
replaceAnyway = new HashSet<Integer>(config.getIntList("rollback.replaceAnyway", null)); replaceAnyway = new HashSet<Integer>(config.getIntList("rollback.replaceAnyway", null));
try {
toolQuery = new QueryParams(logblock);
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());
}
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());
}
defaultDist = config.getInt("lookup.defaultDist", 20); defaultDist = config.getInt("lookup.defaultDist", 20);
defaultTime = LogBlock.parseTimeSpec(config.getString("lookup.defaultTime")); defaultTime = Utils.parseTimeSpec(config.getString("lookup.defaultTime").split(" "));
toolID = config.getInt("lookup.toolID", 270); toolID = config.getInt("lookup.toolID", 270);
if (Material.getMaterial(toolID) == null || Material.getMaterial(toolID).isBlock()) 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 Exception("lookup.toolID doesn't appear to be a valid item id");
toolblockID = config.getInt("lookup.toolblockID", 7); toolblockID = config.getInt("lookup.toolblockID", 7);
if (Material.getMaterial(toolblockID) == null || !Material.getMaterial(toolblockID).isBlock() || toolblockID == 0) 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 Exception("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);
final List<String> worldNames = config.getStringList("loggedWorlds", null); final List<String> worldNames = config.getStringList("loggedWorlds", null);
final List<String> worldTables = config.getStringList("tables", null); final List<String> worldTables = config.getStringList("tables", null);
tables = new HashMap<Integer, String>(); tables = new HashMap<Integer, String>();
if (worldNames == null || worldTables == null || worldNames.size() == 0 || worldNames.size() != worldTables.size()) if (worldNames == null || worldTables == null || worldNames.size() == 0 || worldNames.size() != worldTables.size())
throw new Exception("worldNames or worldTables not set properly"); throw new Exception("worldNames or worldTables not set properly");
for (int i = 0; i < worldNames.size(); i++) { for (int i = 0; i < worldNames.size(); i++)
tables.put(worldNames.get(i).hashCode(), worldTables.get(i)); tables.put(worldNames.get(i).hashCode(), worldTables.get(i));
}
} }
} }

View File

@@ -10,19 +10,18 @@ import java.util.TimerTask;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.block.Chest; import org.bukkit.block.ContainerBlock;
import org.bukkit.block.Dispenser;
import org.bukkit.block.Furnace;
import org.bukkit.block.Sign; import org.bukkit.block.Sign;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import de.diddiz.util.BukkitUtils;
public class Consumer extends TimerTask implements Runnable public class Consumer extends TimerTask
{ {
private final LogBlock logblock; private final LogBlock logblock;
private final Logger log; private final Logger log;
@@ -33,15 +32,48 @@ public class Consumer extends TimerTask implements Runnable
private final HashMap<Integer, Integer> lastAttackedEntity = new HashMap<Integer, Integer>(); private final HashMap<Integer, Integer> lastAttackedEntity = new HashMap<Integer, Integer>();
private final HashMap<Integer, Long> lastAttackTime = new HashMap<Integer, Long>(); private final HashMap<Integer, Long> lastAttackTime = new HashMap<Integer, Long>();
Consumer (LogBlock logblock) { Consumer(LogBlock logblock) {
this.logblock = logblock; this.logblock = logblock;
log = logblock.getServer().getLogger(); log = logblock.getServer().getLogger();
config = logblock.getConfig(); config = logblock.getConfig();
} }
int getQueueSize() {
return bqueue.size() + kqueue.size();
}
boolean hide(Player player) {
final int hash = player.getName().hashCode();
if (hiddenplayers.contains(hash)) {
hiddenplayers.remove(hash);
return false;
}
hiddenplayers.add(hash);
return true;
}
/**
* Logs any block change. Don't try to combine broken and placed blocks. Queue two block changes or use the queueBLockReplace methods.
*/
public void queueBlock(String playerName, Location loc, int typeBefore, int typeAfter, byte data) {
queueBlock(playerName, loc, typeBefore, typeAfter, data, null, null);
}
private void queueBlock(String playerName, Location loc, int typeBefore, int typeAfter, byte data, String signtext, ChestAccess ca) {
if (playerName == null || loc == null || typeBefore < 0 || typeAfter < 0 || hiddenplayers.contains(playerName.hashCode()) || !config.tables.containsKey(loc.getWorld().getName().hashCode()))
return;
if (playerName.length() > 32)
playerName = playerName.substring(0, 32);
if (signtext != null)
signtext = signtext.replace("\\", "\\\\").replace("'", "\\'");
bqueue.add(new BlockRow(loc.getWorld().getName().hashCode(), playerName, typeBefore, typeAfter, data, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), signtext, ca));
}
/** /**
* Logs a block break. The type afterwards is assumed to be o (air). * Logs a block break. The type afterwards is assumed to be o (air).
* @param before Blockstate of the block before actually being destroyed. *
* @param before
* Blockstate of the block before actually being destroyed.
*/ */
public void queueBlockBreak(String playerName, BlockState before) { public void queueBlockBreak(String playerName, BlockState before) {
queueBlockBreak(playerName, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData()); queueBlockBreak(playerName, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData());
@@ -56,7 +88,9 @@ public class Consumer extends TimerTask implements Runnable
/** /**
* Logs a block place. The block type before is assumed to be o (air). * Logs a block place. The block type before is assumed to be o (air).
* @param after Blockstate of the block after actually being placed. *
* @param after
* Blockstate of the block after actually being placed.
*/ */
public void queueBlockPlace(String playerName, BlockState after) { public void queueBlockPlace(String playerName, BlockState after) {
queueBlockPlace(playerName, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), after.getTypeId(), after.getRawData()); queueBlockPlace(playerName, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), after.getTypeId(), after.getRawData());
@@ -70,97 +104,87 @@ public class Consumer extends TimerTask implements Runnable
} }
/** /**
* @param before Blockstate of the block before actually being destroyed. * @param before
* @param after Blockstate of the block after actually being placed. * Blockstate of the block before actually being destroyed.
* @param after
* Blockstate of the block after actually being placed.
*/ */
public void queueBlockReplace(String playerName, BlockState before, BlockState after) { public void queueBlockReplace(String playerName, BlockState before, BlockState after) {
queueBlockReplace(playerName, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData(), after.getTypeId(), after.getRawData()); queueBlockReplace(playerName, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData(), after.getTypeId(), after.getRawData());
} }
/** /**
* @param before Blockstate of the block before actually being destroyed. * @param before
* Blockstate of the block before actually being destroyed.
*/ */
public void queueBlockReplace(String playerName, BlockState before, int typeAfter, byte dataAfter) { public void queueBlockReplace(String playerName, BlockState before, int typeAfter, byte dataAfter) {
queueBlockReplace(playerName, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData(), typeAfter, dataAfter); queueBlockReplace(playerName, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData(), typeAfter, dataAfter);
} }
/** /**
* @param after Blockstate of the block after actually being placed. * @param after
* Blockstate of the block after actually being placed.
*/ */
public void queueBlockReplace(String playerName, int typeBefore, byte dataBefore, BlockState after) { public void queueBlockReplace(String playerName, int typeBefore, byte dataBefore, BlockState after) {
queueBlockReplace(playerName, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), typeBefore, dataBefore, after.getTypeId(), after.getRawData()); queueBlockReplace(playerName, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), typeBefore, dataBefore, after.getTypeId(), after.getRawData());
} }
public void queueBlockReplace(String playerName, Location loc, int typeBefore, byte dataBefore, int typeAfter, byte dataAfter) { public void queueBlockReplace(String playerName, Location loc, int typeBefore, byte dataBefore, int typeAfter, byte dataAfter) {
if (dataBefore == 0) { if (dataBefore == 0)
queueBlock(playerName, loc, typeBefore, typeAfter, dataAfter); queueBlock(playerName, loc, typeBefore, typeAfter, dataAfter);
} else { else {
queueBlockBreak(playerName, loc, typeBefore, dataBefore); queueBlockBreak(playerName, loc, typeBefore, dataBefore);
queueBlockPlace(playerName, loc, typeAfter, dataAfter); queueBlockPlace(playerName, loc, typeAfter, dataAfter);
} }
} }
/** /**
* Logs any block change. Don't try to combine broken and placed blocks. Queue two block changes or use the queueBLockReplace methods. * @param container
* The respective container. Must be an instance of Chest, Dispencer or Furnace.
* @param inType
* Type id of the item traded in. May be 0 to indicate nothing traded in.
* @param outType
* Type id of the item traded out. May be 0 to indicate nothing traded out.
*/ */
public void queueBlock(String playerName, Location loc, int typeBefore, int typeAfter, byte data) { public void queueChestAccess(String playerName, BlockState container, short itemType, short itemAmount, byte itemData) {
queueBlock(playerName, loc, typeBefore, typeAfter, data, null, null); if (!(container instanceof ContainerBlock))
return;
queueChestAccess(playerName, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getTypeId(), itemType, itemAmount, itemData);
} }
/** /**
* @param container The respective container. Must be an instance of Chest, Dispencer or Furnace. * @param type
* @param inType Type id of the item traded in. May be 0 to indicate nothing traded in. * Type id of the container. Must be 63 or 68.
* @param outType Type id of the item traded out. May be 0 to indicate nothing traded out. * @param inType
* Type id of the item traded in. May be 0 to indicate nothing traded in.
* @param outType
* Type id of the item traded out. May be 0 to indicate nothing traded out.
*/ */
public void queueChestAccess(String playerName, BlockState container, short inType, byte inAmount, short outType, byte outAmount) { public void queueChestAccess(String playerName, Location loc, int type, short itemType, short itemAmount, byte itemData) {
if (!(container instanceof Chest) && !(container instanceof Furnace) && !(container instanceof Dispenser)) queueBlock(playerName, loc, type, type, (byte)0, null, new ChestAccess(itemType, itemAmount, itemData));
}
public void queueContainerBreak(String playerName, BlockState container) {
if (!(container instanceof ContainerBlock))
return; return;
queueChestAccess(playerName, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getTypeId(), inType, inAmount, outType, outAmount); queueContainerBreak(playerName, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getTypeId(), container.getRawData(), ((ContainerBlock)container).getInventory());
}
public void queueContainerBreak(String playerName, Location loc, int type, byte data, Inventory inv) {
final ItemStack[] items = BukkitUtils.compressInventory(inv.getContents());
for (final ItemStack item : items)
queueChestAccess(playerName, loc, type, (short)item.getTypeId(), (short)(item.getAmount() * -1), BukkitUtils.rawData(item));
queueBlockBreak(playerName, loc, type, data);
} }
/** /**
* @param type Type id of the container. Must be 63 or 68. * @param killer
* @param inType Type id of the item traded in. May be 0 to indicate nothing traded in. * Can' be null
* @param outType Type id of the item traded out. May be 0 to indicate nothing traded out. * @param victim
*/ * Can' be null
public void queueChestAccess(String playerName, Location loc, int type, short inType, byte inAmount, short outType, byte outAmount) {
queueBlock(playerName, loc, type, type, (byte)0, null, new ChestAccess(inType, inAmount, outType, outAmount));
}
public void queueSign(String playerName, Sign sign) {
queueSign(playerName, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getTypeId(), sign.getRawData(), "sign [" + sign.getLine(0) + "] [" + sign.getLine(1) + "] [" + sign.getLine(2) + "] [" + sign.getLine(3) + "]");
}
/**
* @param type Type of the sign. Must be 63 or 68.
* @param signtext The whole text on the sign in a format like: sign [] [] [] []
*/
public void queueSign(String playerName, Location loc, int type, byte data, String signtext) {
if (type != 63 && type != 68)
return;
queueBlock(playerName, loc, 0, type, data, signtext, null);
}
private void queueBlock(String playerName, Location loc, int typeBefore, int typeAfter, byte data, String signtext, ChestAccess ca) {
if (playerName == null || loc == null || typeBefore < 0 || typeAfter < 0)
return;
if (hiddenplayers.contains(playerName.hashCode()))
return;
if (!config.tables.containsKey(loc.getWorld().getName().hashCode()))
return;
if (playerName.length() > 32)
playerName = playerName.substring(0, 32);
if (signtext != null)
signtext = signtext.replace("\\", "\\\\").replace("'", "\\'");
bqueue.add(new BlockRow(loc.getWorld().getName().hashCode(), playerName, typeBefore, typeAfter, data, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ(), signtext, ca));
}
/**
* @param killer Can' be null
* @param victim Can' be null
*/ */
public void queueKill(Entity killer, Entity victim) { public void queueKill(Entity killer, Entity victim) {
if (killer == null || victim == null) if (killer == null || victim == null)
return; return;
if (lastAttackedEntity.containsKey(killer.getEntityId()) && lastAttackedEntity.get(killer.getEntityId()) == victim.getEntityId() && System.currentTimeMillis() - lastAttackTime.get(killer.getEntityId()) < 5000) if (lastAttackedEntity.containsKey(killer.getEntityId()) && lastAttackedEntity.get(killer.getEntityId()) == victim.getEntityId() && System.currentTimeMillis() - lastAttackTime.get(killer.getEntityId()) < 5000)
return; return;
@@ -169,14 +193,18 @@ public class Consumer extends TimerTask implements Runnable
weapon = ((Player)killer).getItemInHand().getTypeId(); weapon = ((Player)killer).getItemInHand().getTypeId();
lastAttackedEntity.put(killer.getEntityId(), victim.getEntityId()); lastAttackedEntity.put(killer.getEntityId(), victim.getEntityId());
lastAttackTime.put(killer.getEntityId(), System.currentTimeMillis()); lastAttackTime.put(killer.getEntityId(), System.currentTimeMillis());
queueKill(victim.getWorld(), getEntityName(killer), getEntityName(victim), weapon); queueKill(victim.getWorld(), BukkitUtils.getEntityName(killer), BukkitUtils.getEntityName(victim), weapon);
} }
/** /**
* @param world World the victim was inside. * @param world
* @param killerName Name of the killer. Can be null. * World the victim was inside.
* @param victimName Name of the victim. Can't be null. * @param killerName
* @param weapon Item id of the weapon. 0 for no weapon. * Name of the killer. Can be null.
* @param victimName
* Name of the victim. Can't be null.
* @param weapon
* Item id of the weapon. 0 for no weapon.
*/ */
public void queueKill(World world, String killerName, String victimName, int weapon) { public void queueKill(World world, String killerName, String victimName, int weapon) {
if (victimName == null || !config.tables.containsKey(world.getName().hashCode())) if (victimName == null || !config.tables.containsKey(world.getName().hashCode()))
@@ -184,19 +212,36 @@ public class Consumer extends TimerTask implements Runnable
kqueue.add(new KillRow(world.getName().hashCode(), killerName, victimName, weapon)); kqueue.add(new KillRow(world.getName().hashCode(), killerName, victimName, weapon));
} }
int getQueueSize() { /**
return bqueue.size() + kqueue.size(); * @param type
* Type of the sign. Must be 63 or 68.
* @param lines
* The four lines on the sign.
*/
public void queueSignBreak(String playerName, Location loc, int type, byte data, String[] lines) {
if (type != 63 && type != 68 || lines == null || lines.length != 4)
return;
queueBlock(playerName, loc, type, 0, data, lines[0] + "\0" + lines[1] + "\0" + lines[2] + "\0" + lines[3], null);
} }
boolean hide(Player player) { public void queueSignBreak(String playerName, Sign sign) {
final int hash = player.getName().hashCode(); queueSignBreak(playerName, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getTypeId(), sign.getRawData(), sign.getLines());
if (hiddenplayers.contains(hash)) { }
hiddenplayers.remove(hash);
return false; /**
} else { * @param type
hiddenplayers.add(hash); * Type of the sign. Must be 63 or 68.
return true; * @param lines
} * The four lines on the sign.
*/
public void queueSignPlace(String playerName, Location loc, int type, byte data, String[] lines) {
if (type != 63 && type != 68 || lines == null || lines.length != 4)
return;
queueBlock(playerName, loc, 0, type, data, lines[0] + "\0" + lines[1] + "\0" + lines[2] + "\0" + lines[3], null);
}
public void queueSignPlace(String playerName, Sign sign) {
queueSignPlace(playerName, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getTypeId(), sign.getRawData(), sign.getLines());
} }
@Override @Override
@@ -205,7 +250,9 @@ public class Consumer extends TimerTask implements Runnable
if (conn == null) if (conn == null)
return; return;
Statement state = null; Statement state = null;
BlockRow b; KillRow k; String table; BlockRow b;
KillRow k;
String table;
if (getQueueSize() > 1000) if (getQueueSize() > 1000)
log.info("[LogBlock Consumer] Queue overloaded. Size: " + getQueueSize()); log.info("[LogBlock Consumer] Queue overloaded. Size: " + getQueueSize());
try { try {
@@ -214,7 +261,7 @@ public class Consumer extends TimerTask implements Runnable
final long start = System.currentTimeMillis(); final long start = System.currentTimeMillis();
int count = 0; int count = 0;
if (!bqueue.isEmpty()) { if (!bqueue.isEmpty()) {
while (count < config.maxCountPerRun && !bqueue.isEmpty() && (System.currentTimeMillis() - start < config.maxTimePerRun || count < config.minCountPerRun)) { while (!bqueue.isEmpty() && (System.currentTimeMillis() - start < config.timePerRun || count < config.forceToProcessAtLeast)) {
b = bqueue.poll(); b = bqueue.poll();
if (b == null) if (b == null)
continue; continue;
@@ -225,13 +272,13 @@ public class Consumer extends TimerTask implements Runnable
if (keys.next()) if (keys.next())
state.execute("INSERT INTO `" + table + "-sign` (id, signtext) values (" + keys.getInt(1) + ", '" + b.signtext + "')"); state.execute("INSERT INTO `" + table + "-sign` (id, signtext) values (" + keys.getInt(1) + ", '" + b.signtext + "')");
else else
log.severe("[LogBlock Consumer] Failed to get generated keys"); log.warning("[LogBlock Consumer] Failed to get generated keys. Unable to log sign text.");
} else if (b.ca != null) { } else if (b.ca != null) {
final ResultSet keys = state.getGeneratedKeys(); final ResultSet keys = state.getGeneratedKeys();
if (keys.next()) if (keys.next())
state.execute("INSERT INTO `" + table + "-chest` (id, intype, inamount, outtype, outamount) values (" + keys.getInt(1) + ", " + b.ca.inType + ", " + b.ca.inAmount + ", " + b.ca.outType + ", " + b.ca.outAmount + ")"); state.execute("INSERT INTO `" + table + "-chest` (id, itemtype, itemamount, itemdata) values (" + keys.getInt(1) + ", " + b.ca.itemType + ", " + b.ca.itemAmount + ", " + b.ca.itemData + ")");
else else
log.severe("[LogBlock Consumer] Failed to get generated keys"); log.warning("[LogBlock Consumer] Failed to get generated keys. Unable to log chest access.");
} }
count++; count++;
if (count % 100 == 0) if (count % 100 == 0)
@@ -240,7 +287,7 @@ public class Consumer extends TimerTask implements Runnable
conn.commit(); conn.commit();
} }
if (!kqueue.isEmpty()) { if (!kqueue.isEmpty()) {
while (count < config.maxCountPerRun && !kqueue.isEmpty() && (System.currentTimeMillis() - start < config.maxTimePerRun || count < config.minCountPerRun)) { while (!kqueue.isEmpty() && (System.currentTimeMillis() - start < config.timePerRun || count < config.forceToProcessAtLeast)) {
k = kqueue.poll(); k = kqueue.poll();
if (k == null) if (k == null)
continue; continue;
@@ -255,38 +302,16 @@ public class Consumer extends TimerTask implements Runnable
log.log(Level.SEVERE, "[LogBlock Consumer] SQL exception", ex); log.log(Level.SEVERE, "[LogBlock Consumer] SQL exception", ex);
} finally { } finally {
try { try {
if (conn != null)
conn.close();
if (state != null) if (state != null)
state.close(); state.close();
conn.close();
} catch (final SQLException ex) { } catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock Consumer] SQL exception on close", ex); log.log(Level.SEVERE, "[LogBlock Consumer] SQL exception on close", ex);
} }
} }
} }
private String getEntityName(Entity entity) { private static class BlockRow
if (entity instanceof Player)
return ((Player)entity).getName();
if (entity instanceof TNTPrimed)
return "TNT";
return entity.getClass().getSimpleName().substring(5);
}
private class ChestAccess
{
public short inType, outType;
public byte inAmount, outAmount;
ChestAccess(short inType, byte inAmount, short outType, byte outAmount) {
this.inType = inType;
this.inAmount = inAmount;
this.outType = outType;
this.outAmount = outAmount;
}
}
private class BlockRow
{ {
public final int worldHash; public final int worldHash;
public final String name; public final String name;
@@ -296,7 +321,7 @@ public class Consumer extends TimerTask implements Runnable
public final String signtext; public final String signtext;
public final ChestAccess ca; public final ChestAccess ca;
BlockRow(int worldHash, String name, int replaced, int type, byte data, int x, int y, int z, String signtext, ChestAccess ca) { BlockRow(int worldHash, String name, int replaced, int type, byte data, int x, int y, int z, String signtext, ChestAccess ca) {
this.worldHash = worldHash; this.worldHash = worldHash;
this.name = name; this.name = name;
this.replaced = replaced; this.replaced = replaced;
@@ -310,7 +335,19 @@ public class Consumer extends TimerTask implements Runnable
} }
} }
private class KillRow private static class ChestAccess
{
public final short itemType, itemAmount;
public final byte itemData;
ChestAccess(short itemType, short itemAmount, byte itemData) {
this.itemType = itemType;
this.itemAmount = itemAmount;
this.itemData = itemData;
}
}
private static class KillRow
{ {
public final int worldHash; public final int worldHash;
public final String killer; public final String killer;
@@ -323,24 +360,5 @@ public class Consumer extends TimerTask implements Runnable
victim = defender; victim = defender;
this.weapon = weapon; this.weapon = weapon;
} }
@Override
public int hashCode() {
return killer.hashCode() * 31 + victim.hashCode();
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
final KillRow k = (KillRow)obj;
if (!killer.equals(k.killer))
return false;
if (!victim.equals(k.victim))
return false;
return true;
}
} }
} }

View File

@@ -1,8 +1,8 @@
package de.diddiz.LogBlock; package de.diddiz.LogBlock;
import org.bukkit.Material;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import org.bukkit.event.block.BlockBreakEvent; import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.block.BlockBurnEvent;
import org.bukkit.event.block.BlockFromToEvent; import org.bukkit.event.block.BlockFromToEvent;
@@ -11,14 +11,16 @@ import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.block.LeavesDecayEvent; import org.bukkit.event.block.LeavesDecayEvent;
import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.block.SignChangeEvent;
public class LBBlockListener extends BlockListener class LBBlockListener extends BlockListener
{ {
private final Config config;
private final Consumer consumer; private final Consumer consumer;
private final boolean logSignTexts;
private final boolean logChestAccess;
LBBlockListener(LogBlock logblock) { LBBlockListener(LogBlock logblock) {
config = logblock.getConfig();
consumer = logblock.getConsumer(); consumer = logblock.getConsumer();
logSignTexts = logblock.getConfig().logSignTexts;
logChestAccess = logblock.getConfig().logChestAccess;
} }
@Override @Override
@@ -26,22 +28,23 @@ public class LBBlockListener extends BlockListener
if (!event.isCancelled()) { if (!event.isCancelled()) {
final int typeFrom = event.getBlock().getTypeId(); final int typeFrom = event.getBlock().getTypeId();
final int typeTo = event.getToBlock().getTypeId(); final int typeTo = event.getToBlock().getTypeId();
if (typeFrom == 10 || typeFrom == 11) { if (typeFrom == 10 || typeFrom == 11)
if (typeTo == 0 || typeTo == 78) if (typeTo == 0 || typeTo == 78)
consumer.queueBlockReplace("LavaFlow", event.getToBlock().getState(), 10, (byte)(event.getBlock().getData() + 1)); consumer.queueBlockReplace("LavaFlow", event.getToBlock().getState(), 10, (byte)(event.getBlock().getData() + 1));
else if (typeTo == 8 || typeTo == 9) { else if (typeTo == 8 || typeTo == 9)
if (event.getFace() == BlockFace.DOWN) if (event.getFace() == BlockFace.DOWN)
consumer.queueBlockReplace("LavaFlow", event.getToBlock().getState(), 10, (byte)0); consumer.queueBlockReplace("LavaFlow", event.getToBlock().getState(), 10, (byte)0);
else else
consumer.queueBlockReplace("LavaFlow", event.getToBlock().getState(), 4, (byte)0); consumer.queueBlockReplace("LavaFlow", event.getToBlock().getState(), 4, (byte)0);
}
}
} }
} }
@Override @Override
public void onBlockPlace(BlockPlaceEvent event) { public void onBlockPlace(BlockPlaceEvent event) {
if (!event.isCancelled() && !(config.logSignTexts && (event.getBlock().getType() == Material.WALL_SIGN || event.getBlock().getType() == Material.SIGN_POST))) { if (!event.isCancelled()) {
final int type = event.getBlock().getTypeId();
if (logSignTexts && (type == 63 || type == 68))
return;
final BlockState before = event.getBlockReplacedState(); final BlockState before = event.getBlockReplacedState();
final BlockState after = event.getBlockPlaced().getState(); final BlockState after = event.getBlockPlaced().getState();
if (before.getTypeId() == 0) if (before.getTypeId() == 0)
@@ -53,14 +56,21 @@ public class LBBlockListener extends BlockListener
@Override @Override
public void onBlockBreak(BlockBreakEvent event) { public void onBlockBreak(BlockBreakEvent event) {
if (!event.isCancelled()) if (!event.isCancelled()) {
consumer.queueBlockBreak(event.getPlayer().getName(), event.getBlock().getState()); final int type = event.getBlock().getTypeId();
if (logSignTexts && (type == 63 || type == 68))
consumer.queueSignBreak(event.getPlayer().getName(), (Sign)event.getBlock().getState());
else if (logChestAccess && (type == 23 || type == 54 || type == 61))
consumer.queueContainerBreak(event.getPlayer().getName(), event.getBlock().getState());
else
consumer.queueBlockBreak(event.getPlayer().getName(), event.getBlock().getState());
}
} }
@Override @Override
public void onSignChange(SignChangeEvent event) { public void onSignChange(SignChangeEvent event) {
if (!event.isCancelled()) if (!event.isCancelled())
consumer.queueSign(event.getPlayer().getName(), event.getBlock().getLocation(), event.getBlock().getTypeId(), event.getBlock().getData(), "sign [" + event.getLine(0) + "] [" + event.getLine(1) + "] [" + event.getLine(2) + "] [" + event.getLine(3) + "]"); consumer.queueSignPlace(event.getPlayer().getName(), event.getBlock().getLocation(), event.getBlock().getTypeId(), event.getBlock().getData(), event.getLines());
} }
@Override @Override

View File

@@ -0,0 +1,86 @@
package de.diddiz.LogBlock;
import java.util.HashMap;
import org.bukkit.Location;
import org.bukkit.block.BlockState;
import org.bukkit.block.ContainerBlock;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerListener;
import org.bukkit.event.player.PlayerMoveEvent;
import org.bukkit.event.player.PlayerQuitEvent;
import org.bukkit.inventory.ItemStack;
import de.diddiz.util.BukkitUtils;
class LBChestAccessListener extends PlayerListener
{
private final Consumer consumer;
private final HashMap<Integer, Container> containers = new HashMap<Integer, Container>();
LBChestAccessListener(LogBlock logblock) {
consumer = logblock.getConsumer();
}
private void logChestAccess(String playerName) {
final Container container = containers.get(playerName.hashCode());
final Location loc = container.getLocation();
final ItemStack[] after = BukkitUtils.compressInventory(((ContainerBlock)loc.getWorld().getBlockAt(loc).getState()).getInventory().getContents());
final ItemStack[] diff = BukkitUtils.compareInventories(container.getContent(), after);
for (final ItemStack item : diff)
consumer.queueChestAccess(playerName, loc, container.getTypeId(), (short)item.getTypeId(), (short)item.getAmount(), BukkitUtils.rawData(item));
containers.remove(playerName.hashCode());
}
@Override
public void onPlayerInteract(PlayerInteractEvent event) {
if (containers.containsKey(event.getPlayer().getName().hashCode()))
logChestAccess(event.getPlayer().getName());
if (!event.isCancelled() && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
final BlockState state = event.getClickedBlock().getState();
if (state instanceof ContainerBlock)
containers.put(event.getPlayer().getName().hashCode(), new Container(state));
}
}
@Override
public void onPlayerMove(PlayerMoveEvent event) {
final Container container = containers.get(event.getPlayer().getName().hashCode());
if (container != null && !container.isSliding())
logChestAccess(event.getPlayer().getName());
}
@Override
public void onPlayerQuit(PlayerQuitEvent event) {
if (containers.containsKey(event.getPlayer().getName().hashCode()))
logChestAccess(event.getPlayer().getName());
}
private static class Container
{
private final ItemStack[] content;
private final BlockState state;
private final long start;
Container(BlockState state) {
this.state = state;
content = BukkitUtils.compressInventory(((ContainerBlock)state).getInventory().getContents());
start = System.currentTimeMillis();
}
ItemStack[] getContent() {
return content;
}
Location getLocation() {
return new Location(state.getWorld(), state.getX(), state.getY(), state.getZ());
}
int getTypeId() {
return state.getTypeId();
}
boolean isSliding() {
return System.currentTimeMillis() - start < 500;
}
}
}

View File

@@ -1,6 +1,7 @@
package de.diddiz.LogBlock; package de.diddiz.LogBlock;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.entity.Creeper; import org.bukkit.entity.Creeper;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.Fireball; import org.bukkit.entity.Fireball;
@@ -13,14 +14,20 @@ import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntityExplodeEvent;
import org.bukkit.event.entity.EntityListener; import org.bukkit.event.entity.EntityListener;
public class LBEntityListener extends EntityListener class LBEntityListener extends EntityListener
{ {
private final Config config;
private final Consumer consumer; private final Consumer consumer;
private final boolean logSignTexts;
private final boolean logChestAccess;
private final boolean logCreeperExplosionsAsPlayer;
private final Config.LogKillsLevel logKillsLevel;
LBEntityListener(LogBlock logblock) { LBEntityListener(LogBlock logblock) {
config= logblock.getConfig();
consumer = logblock.getConsumer(); consumer = logblock.getConsumer();
logSignTexts = logblock.getConfig().logSignTexts;
logChestAccess = logblock.getConfig().logChestAccess;
logCreeperExplosionsAsPlayer = logblock.getConfig().logCreeperExplosionsAsPlayerWhoTriggeredThese;
logKillsLevel = logblock.getConfig().logKillsLevel;
} }
@Override @Override
@@ -29,14 +36,28 @@ public class LBEntityListener extends EntityListener
String name; String name;
if (event.getEntity() instanceof TNTPrimed) if (event.getEntity() instanceof TNTPrimed)
name = "TNT"; name = "TNT";
else if (event.getEntity() instanceof Creeper) else if (event.getEntity() instanceof Creeper) {
name = "Creeper"; if (logCreeperExplosionsAsPlayer) {
else if (event.getEntity() instanceof Fireball) final Entity target = ((Creeper)event.getEntity()).getTarget();
if (target instanceof Player)
name = ((Player)target).getName();
else
name = "Creeper";
} else
name = "Creeper";
} else if (event.getEntity() instanceof Fireball)
name = "Ghast"; name = "Ghast";
else else
name = "Environment"; name = "Environment";
for (final Block block : event.blockList()) for (final Block block : event.blockList()) {
consumer.queueBlockBreak(name, block.getState()); final int type = block.getTypeId();
if (logSignTexts & (type == 63 || type == 68))
consumer.queueSignBreak(name, (Sign)block.getState());
else if (logChestAccess && (type == 23 || type == 54 || type == 61))
consumer.queueContainerBreak(name, block.getState());
else
consumer.queueBlockBreak(name, block.getState());
}
} }
} }
@@ -46,11 +67,11 @@ public class LBEntityListener extends EntityListener
return; return;
final LivingEntity victim = (LivingEntity)event.getEntity(); final LivingEntity victim = (LivingEntity)event.getEntity();
final Entity killer = ((EntityDamageByEntityEvent)event).getDamager(); final Entity killer = ((EntityDamageByEntityEvent)event).getDamager();
if (victim.getHealth() - event.getDamage() > 0 || victim.getHealth() <= 0 ) if (victim.getHealth() - event.getDamage() > 0 || victim.getHealth() <= 0)
return; return;
if (config.logKillsLevel == Config.LogKillsLevel.PLAYERS && !(victim instanceof Player && killer instanceof Player)) if (logKillsLevel == Config.LogKillsLevel.PLAYERS && !(victim instanceof Player && killer instanceof Player))
return; return;
else if (config.logKillsLevel == Config.LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster) && killer instanceof Player || killer instanceof Monster)) else if (logKillsLevel == Config.LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster) && killer instanceof Player || killer instanceof Monster))
return; return;
consumer.queueKill(killer, victim); consumer.queueKill(killer, victim);
} }

View File

@@ -5,16 +5,13 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerBucketEmptyEvent; import org.bukkit.event.player.PlayerBucketEmptyEvent;
import org.bukkit.event.player.PlayerBucketFillEvent; import org.bukkit.event.player.PlayerBucketFillEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerListener; import org.bukkit.event.player.PlayerListener;
public class LBPlayerListener extends PlayerListener class LBPlayerListener extends PlayerListener
{ {
private final Logger log; private final Logger log;
private final LogBlock logblock; private final LogBlock logblock;
@@ -26,12 +23,6 @@ public class LBPlayerListener extends PlayerListener
consumer = logblock.getConsumer(); consumer = logblock.getConsumer();
} }
@Override
public void onPlayerInteract(PlayerInteractEvent event) {
if (!event.isCancelled() && event.getAction() == Action.RIGHT_CLICK_BLOCK && (event.getClickedBlock().getType() == Material.CHEST || event.getClickedBlock().getType() == Material.FURNACE ||event.getClickedBlock().getType() == Material.DISPENSER))
consumer.queueChestAccess(event.getPlayer().getName(), event.getClickedBlock().getLocation(), event.getClickedBlock().getTypeId(),(short)0, (byte)0, (short)0, (byte)0);
}
@Override @Override
public void onPlayerBucketFill(PlayerBucketFillEvent event) { public void onPlayerBucketFill(PlayerBucketFillEvent event) {
if (!event.isCancelled()) if (!event.isCancelled())
@@ -63,8 +54,7 @@ public class LBPlayerListener extends PlayerListener
try { try {
if (state != null) if (state != null)
state.close(); state.close();
if (conn != null) conn.close();
conn.close();
} catch (final SQLException ex) { } catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock] SQL exception on close", ex); log.log(Level.SEVERE, "[LogBlock] SQL exception on close", ex);
} }

View File

@@ -0,0 +1,54 @@
package de.diddiz.LogBlock;
import org.bukkit.ChatColor;
import org.bukkit.entity.Player;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerListener;
class LBToolListener extends PlayerListener
{
private final LogBlock logblock;
private final Config config;
private final CommandsHandler handler;
LBToolListener(LogBlock logblock) {
this.logblock = logblock;
config = logblock.getConfig();
handler = logblock.getCommandsHandler();
}
@Override
public void onPlayerInteract(PlayerInteractEvent event) {
if (!event.isCancelled()) {
final Player player = event.getPlayer();
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getMaterial().getId() == config.toolID && logblock.hasPermission(player, "logblock.tool") && logblock.getSession(player.getName()).toolEnabled) {
if (config.tables.get(player.getWorld().getName().hashCode()) != null) {
try {
final QueryParams params = logblock.getSession(player.getName()).toolQuery;
params.loc = event.getClickedBlock().getLocation();
params.world = player.getWorld();
handler.new CommandLookup(player, params);
} catch (final Exception ex) {
player.sendMessage(ChatColor.RED + ex.getMessage());
}
if (event.getClickedBlock().getTypeId() != 26)
event.setCancelled(true);
} else
player.sendMessage("This world isn't logged");
} else if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getMaterial().getId() == config.toolblockID && logblock.hasPermission(player, "logblock.toolblock") && logblock.getSession(player.getName()).toolBlockEnabled)
if (config.tables.get(player.getWorld().getName().hashCode()) != null) {
try {
final QueryParams params = logblock.getSession(player.getName()).toolQuery;
params.loc = event.getClickedBlock().getFace(event.getBlockFace()).getLocation();
params.world = player.getWorld();
handler.new CommandLookup(player, params);
} catch (final Exception ex) {
player.sendMessage(ChatColor.RED + ex.getMessage());
}
event.setCancelled(true);
} else
player.sendMessage("This world isn't logged");
}
}
}

View File

@@ -1,31 +0,0 @@
package de.diddiz.LogBlock;
import org.bukkit.Material;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerListener;
public class LBToolPlayerListener extends PlayerListener
{
private final LogBlock logblock;
private final Config config;
LBToolPlayerListener(LogBlock logblock) {
this.logblock = logblock;
config = logblock.getConfig();
}
@Override
public void onPlayerInteract(PlayerInteractEvent event) {
if (!event.isCancelled()) {
if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getMaterial().getId() == config.toolID && logblock.checkPermission(event.getPlayer(), "logblock.lookup")) {
logblock.getServer().getScheduler().scheduleAsyncDelayedTask(logblock, new BlockStats(logblock, event.getPlayer(), event.getClickedBlock()));
if (event.getClickedBlock().getType() != Material.BED_BLOCK)
event.setCancelled(true);
} else if (event.getAction() == Action.RIGHT_CLICK_BLOCK && event.getMaterial().getId() == config.toolblockID && logblock.checkPermission(event.getPlayer(), "logblock.lookup")) {
logblock.getServer().getScheduler().scheduleAsyncDelayedTask(logblock, new BlockStats(logblock, event.getPlayer(), event.getClickedBlock().getFace(event.getBlockFace())));
event.setCancelled(true);
}
}
}
}

View File

@@ -12,19 +12,21 @@ import java.util.Map;
import java.util.Timer; import java.util.Timer;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.Event.Priority; import org.bukkit.event.Event.Priority;
import org.bukkit.event.Event.Type; import org.bukkit.event.Event.Type;
import org.bukkit.plugin.PluginManager; import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin; import org.bukkit.plugin.java.JavaPlugin;
import com.nijiko.permissions.PermissionHandler; import com.nijiko.permissions.PermissionHandler;
import com.nijikokun.bukkit.Permissions.Permissions; import com.nijikokun.bukkit.Permissions.Permissions;
import de.diddiz.LogBlock.QueryParams.BlockChangeType;
import de.diddiz.util.ConnectionPool; import de.diddiz.util.ConnectionPool;
import de.diddiz.util.Download; import de.diddiz.util.Utils;
// TODO Add painting logging
// TODO Add Button, lever etc logging
public class LogBlock extends JavaPlugin public class LogBlock extends JavaPlugin
{ {
@@ -32,10 +34,11 @@ public class LogBlock extends JavaPlugin
private Config config; private Config config;
private ConnectionPool pool; private ConnectionPool pool;
private Consumer consumer = null; private Consumer consumer = null;
private CommandsHandler commandsHandler;
private Timer timer = null; private Timer timer = null;
private PermissionHandler permissions = null; private PermissionHandler permissions = null;
private boolean errorAtLoading = false; private boolean errorAtLoading = false;
private Map<Integer, Session> sessions = new HashMap<Integer, Session>(); private final Map<Integer, Session> sessions = new HashMap<Integer, Session>();
public Config getConfig() { public Config getConfig() {
return config; return config;
@@ -45,10 +48,14 @@ public class LogBlock extends JavaPlugin
return consumer; return consumer;
} }
public CommandsHandler getCommandsHandler() {
return commandsHandler;
}
@Override @Override
public void onLoad() { public void onLoad() {
log = getServer().getLogger(); log = getServer().getLogger();
try { try {
config = new Config(this); config = new Config(this);
} catch (final Exception ex) { } catch (final Exception ex) {
log.log(Level.SEVERE, "[LogBlock] Exception while reading config:", ex); log.log(Level.SEVERE, "[LogBlock] Exception while reading config:", ex);
@@ -59,7 +66,7 @@ public class LogBlock extends JavaPlugin
try { try {
if (!file.exists() || file.length() == 0) { if (!file.exists() || file.length() == 0) {
log.info("[LogBlock] Downloading " + file.getName() + "..."); log.info("[LogBlock] Downloading " + file.getName() + "...");
Download.download(new URL("http://diddiz.insane-architects.net/download/mysql-connector-java-bin.jar"), file); Utils.download(new URL("http://diddiz.insane-architects.net/download/mysql-connector-java-bin.jar"), file);
} }
if (!file.exists() || file.length() == 0) if (!file.exists() || file.length() == 0)
throw new FileNotFoundException(file.getAbsolutePath() + file.getName()); throw new FileNotFoundException(file.getAbsolutePath() + file.getName());
@@ -71,8 +78,7 @@ public class LogBlock extends JavaPlugin
try { try {
log.info("[LogBlock] Connecting to " + config.user + "@" + config.url + "..."); log.info("[LogBlock] Connecting to " + config.user + "@" + config.url + "...");
pool = new ConnectionPool(config.url, config.user, config.password); pool = new ConnectionPool(config.url, config.user, config.password);
final Connection conn = getConnection(); getConnection().close();
conn.close();
} catch (final Exception ex) { } catch (final Exception ex) {
log.log(Level.SEVERE, "[LogBlock] Exception while checking database connection", ex); log.log(Level.SEVERE, "[LogBlock] Exception while checking database connection", ex);
errorAtLoading = true; errorAtLoading = true;
@@ -92,19 +98,28 @@ public class LogBlock extends JavaPlugin
getServer().getPluginManager().disablePlugin(this); getServer().getPluginManager().disablePlugin(this);
return; return;
} }
getCommand("lb").setExecutor(new CommandsHandler(this)); commandsHandler = new CommandsHandler(this);
getCommand("lb").setExecutor(commandsHandler);
if (getServer().getPluginManager().getPlugin("Permissions") != null) { if (getServer().getPluginManager().getPlugin("Permissions") != null) {
permissions = ((Permissions)getServer().getPluginManager().getPlugin("Permissions")).getHandler(); permissions = ((Permissions)getServer().getPluginManager().getPlugin("Permissions")).getHandler();
log.info("[LogBlock] Permissions enabled"); log.info("[LogBlock] Permissions found.");
} else } else
log.info("[LogBlock] Permissions plugin not found. Using default permissions."); log.info("[LogBlock] Permissions plugin not found. Using default permissions.");
if (config.keepLogDays >= 0) if (config.keepLogDays >= 0) {
new Thread(new ClearLog(this)).start(); final QueryParams params = new QueryParams(this);
params.minutes = config.keepLogDays * -1440;
params.bct = BlockChangeType.ALL;
try {
commandsHandler.new CommandClearLog(new ConsoleCommandSender(getServer()), params);
} catch (final Exception ex) {
log.severe("Failed to schedule ClearLog: " + ex.getMessage());
}
}
final LBBlockListener lbBlockListener = new LBBlockListener(this); final LBBlockListener lbBlockListener = new LBBlockListener(this);
final LBPlayerListener lbPlayerListener = new LBPlayerListener(this); final LBPlayerListener lbPlayerListener = new LBPlayerListener(this);
final LBEntityListener lbEntityListener = new LBEntityListener(this); final LBEntityListener lbEntityListener = new LBEntityListener(this);
final PluginManager pm = getServer().getPluginManager(); final PluginManager pm = getServer().getPluginManager();
pm.registerEvent(Type.PLAYER_INTERACT, new LBToolPlayerListener(this), Priority.Normal, this); pm.registerEvent(Type.PLAYER_INTERACT, new LBToolListener(this), Priority.Normal, this);
pm.registerEvent(Type.PLAYER_JOIN, lbPlayerListener, Priority.Monitor, this); pm.registerEvent(Type.PLAYER_JOIN, lbPlayerListener, Priority.Monitor, this);
if (config.logBlockCreations) { if (config.logBlockCreations) {
pm.registerEvent(Type.BLOCK_PLACE, lbBlockListener, Priority.Monitor, this); pm.registerEvent(Type.BLOCK_PLACE, lbBlockListener, Priority.Monitor, this);
@@ -122,8 +137,11 @@ public class LogBlock extends JavaPlugin
pm.registerEvent(Type.ENTITY_EXPLODE, lbEntityListener, Priority.Monitor, this); pm.registerEvent(Type.ENTITY_EXPLODE, lbEntityListener, Priority.Monitor, this);
if (config.logLeavesDecay) if (config.logLeavesDecay)
pm.registerEvent(Type.LEAVES_DECAY, lbBlockListener, Priority.Monitor, this); pm.registerEvent(Type.LEAVES_DECAY, lbBlockListener, Priority.Monitor, this);
if (config.logChestAccess) if (config.logChestAccess) {
pm.registerEvent(Type.PLAYER_INTERACT, lbPlayerListener, Priority.Monitor, this); final LBChestAccessListener chestAccessListener = new LBChestAccessListener(this);
pm.registerEvent(Type.PLAYER_INTERACT, chestAccessListener, Priority.Monitor, this);
pm.registerEvent(Type.PLAYER_MOVE, chestAccessListener, Priority.Monitor, this);
}
if (config.logLavaFlow) if (config.logLavaFlow)
pm.registerEvent(Type.BLOCK_FROMTO, lbBlockListener, Priority.Monitor, this); pm.registerEvent(Type.BLOCK_FROMTO, lbBlockListener, Priority.Monitor, this);
if (config.logKills) if (config.logKills)
@@ -157,7 +175,7 @@ public class LogBlock extends JavaPlugin
} }
} }
if (pool != null) if (pool != null)
pool.closeConnections(); pool.close();
log.info("LogBlock disabled."); log.info("LogBlock disabled.");
} }
@@ -169,17 +187,17 @@ public class LogBlock extends JavaPlugin
try { try {
final DatabaseMetaData dbm = conn.getMetaData(); final DatabaseMetaData dbm = conn.getMetaData();
state = conn.createStatement(); state = conn.createStatement();
if (!dbm.getTables(null, null, "lb-players", null).next()) { if (!dbm.getTables(null, null, "lb-players", null).next()) {
log.log(Level.INFO, "[LogBlock] Crating table lb-players."); 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))"); 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()) if (!dbm.getTables(null, null, "lb-players", null).next())
return false; return false;
} }
state.execute("INSERT IGNORE INTO `lb-players` (playername) VALUES ('TNT'), ('Creeper'), ('Fire'), ('LeavesDecay'), ('Ghast'), ('LavaFlow'), ('Environment'), ('Chicken'), ('Cow'), ('Giant'), ('Pig'), ('PigZombie'), ('Sheep'), ('Skeleton'), ('Slime'), ('Spider'), ('Squid'), ('Wolf'), ('Zombie')"); state.execute("INSERT IGNORE INTO `lb-players` (playername) VALUES ('-'), ('TNT'), ('Creeper'), ('Fire'), ('LeavesDecay'), ('Ghast'), ('LavaFlow'), ('Environment'), ('Chicken'), ('Cow'), ('Giant'), ('Pig'), ('PigZombie'), ('Sheep'), ('Skeleton'), ('Slime'), ('Spider'), ('Squid'), ('Wolf'), ('Zombie')");
for (final String table : config.tables.values()) { for (final String table : config.tables.values()) {
if (!dbm.getTables(null, null, table, null).next()) { if (!dbm.getTables(null, null, table, null).next()) {
log.log(Level.INFO, "[LogBlock] Crating table " + table + "."); log.log(Level.INFO, "[LogBlock] Crating table " + table + ".");
state.execute("CREATE TABLE `" + table + "` (id INT NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL DEFAULT '0000-00-00 00:00:00', playerid SMALLINT UNSIGNED NOT NULL DEFAULT '0', replaced TINYINT UNSIGNED NOT NULL DEFAULT '0', type TINYINT UNSIGNED NOT NULL DEFAULT '0', data TINYINT UNSIGNED NOT NULL DEFAULT '0', x SMALLINT NOT NULL DEFAULT '0', y TINYINT UNSIGNED NOT NULL DEFAULT '0', z SMALLINT NOT NULL DEFAULT '0', PRIMARY KEY (id), KEY coords (y, x, z), KEY date (date));"); 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()) if (!dbm.getTables(null, null, table, null).next())
return false; return false;
} }
@@ -191,7 +209,7 @@ public class LogBlock extends JavaPlugin
} }
if (!dbm.getTables(null, null, table + "-chest", null).next()) { if (!dbm.getTables(null, null, table + "-chest", null).next()) {
log.log(Level.INFO, "[LogBlock] Crating table " + table + "-chest."); log.log(Level.INFO, "[LogBlock] Crating table " + table + "-chest.");
state.execute("CREATE TABLE `" + table + "-chest` (id INT NOT NULL, intype SMALLINT UNSIGNED NOT NULL DEFAULT '0', inamount TINYINT UNSIGNED NOT NULL DEFAULT '0', outtype SMALLINT UNSIGNED NOT NULL DEFAULT '0', outamount TINYINT UNSIGNED NOT NULL DEFAULT '0', PRIMARY KEY (id));"); 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()) if (!dbm.getTables(null, null, table + "-chest", null).next())
return false; return false;
} }
@@ -209,8 +227,7 @@ public class LogBlock extends JavaPlugin
try { try {
if (state != null) if (state != null)
state.close(); state.close();
if (conn != null) conn.close();
conn.close();
} catch (final SQLException ex) { } catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock] SQL exception on close", ex); log.log(Level.SEVERE, "[LogBlock] SQL exception on close", ex);
} }
@@ -218,42 +235,15 @@ public class LogBlock extends JavaPlugin
return false; return false;
} }
boolean checkPermission(CommandSender sender, String permission) { boolean hasPermission(CommandSender sender, String permission) {
if (permissions != null && sender instanceof Player) if (permissions != null && sender instanceof Player)
return permissions.permission((Player)sender, permission); return permissions.permission((Player)sender, permission);
else { if (permission.equals("logblock.lookup") || permission.equals("logblock.hide") || permission.equals("logblock.rollback"))
if (permission.equals("logblock.area")) return sender.isOp();
return sender.isOp(); return true;
else if (permission.equals("logblock.hide"))
return sender.isOp();
else if (permission.equals("logblock.rollback"))
return sender.isOp();
return true;
}
} }
static int parseTimeSpec(String timespec) { Connection getConnection() {
final String[] split = timespec.split(" ");
if (split.length != 2)
return 0;
return parseTimeSpec(split[0], split[1]);
}
static int parseTimeSpec(String time, String unit) {
int min;
try {
min = Integer.parseInt(time);
} catch (final NumberFormatException ex) {
return 0;
}
if (unit.startsWith("hour"))
min *= 60;
else if (unit.startsWith("day"))
min *= 60*24;
return min;
}
public Connection getConnection() {
try { try {
return pool.getConnection(); return pool.getConnection();
} catch (final SQLException ex) { } catch (final SQLException ex) {
@@ -261,11 +251,11 @@ public class LogBlock extends JavaPlugin
return null; return null;
} }
} }
public Session getSession(String playerName) { public Session getSession(String playerName) {
Session session = sessions.get(playerName.hashCode()); Session session = sessions.get(playerName.hashCode());
if (session == null) { if (session == null) {
session = new Session(); session = new Session(this);
sessions.put(playerName.hashCode(), session); sessions.put(playerName.hashCode(), session);
} }
return session; return session;

View File

@@ -1,83 +0,0 @@
package de.diddiz.LogBlock;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
public class PlayerAreaStats implements Runnable
{
private final Logger log;
private final Connection conn;
private final String table;
private final Player player;
private final String name;
private final int size;
PlayerAreaStats(LogBlock logblock, Player player, String name, int size) {
this.player = player;
this.name = name;
this.size = size;
log = logblock.getServer().getLogger();
conn = logblock.getConnection();
table = logblock.getConfig().tables.get(player.getWorld().getName().hashCode());
}
@Override
public void run() {
PreparedStatement ps = null;
ResultSet rs = null;
try {
if (conn == null) {
player.sendMessage(ChatColor.RED + "Failed to create database connection");
return;
}
if (table == null) {
player.sendMessage(ChatColor.RED + "This world isn't logged");
return;
}
conn.setAutoCommit(false);
ps = conn.prepareStatement("SELECT `type`, SUM(`created`) AS `created`, SUM(`destroyed`) AS `destroyed` FROM ((SELECT `type`, count(`type`) AS `created`, 0 AS `destroyed` FROM `" + table + "` INNER JOIN `lb-players` USING (`playerid`) WHERE `playername` = ? AND x > ? AND x < ? AND z > ? AND z < ? AND `type` > 0 AND `type` != `replaced` GROUP BY `type`) UNION (SELECT `replaced` AS `type`, 0 AS `created`, count(`replaced`) AS `destroyed` FROM `" + table + "` INNER JOIN `lb-players` USING (`playerid`) WHERE `playername` = ? AND x > ? AND x < ? AND z > ? AND z < ? AND `replaced` > 0 AND `type` != `replaced` GROUP BY `replaced`)) AS t GROUP BY `type` ORDER BY SUM(`created`) + SUM(`destroyed`) DESC LIMIT 15");
ps.setString(1, name);
ps.setInt(2, player.getLocation().getBlockX()-size);
ps.setInt(3, player.getLocation().getBlockX()+size);
ps.setInt(4, player.getLocation().getBlockZ()-size);
ps.setInt(5, player.getLocation().getBlockZ()+size);
ps.setString(6, name);
ps.setInt(7, player.getLocation().getBlockX()-size);
ps.setInt(8, player.getLocation().getBlockX()+size);
ps.setInt(9, player.getLocation().getBlockZ()-size);
ps.setInt(10, player.getLocation().getBlockZ()+size);
rs = ps.executeQuery();
player.sendMessage(ChatColor.DARK_AQUA + "Player " + name + " within " + size + " blocks of you: ");
if (!rs.next())
player.sendMessage(ChatColor.DARK_AQUA + "No results found.");
else {
player.sendMessage(ChatColor.GOLD + String.format("%-6s %-6s %s", "Creat", "Destr", "Block"));
rs.beforeFirst();
while (rs.next()) {
player.sendMessage(ChatColor.GOLD + String.format("%-6d %-6d %s", rs.getInt("created"), rs.getInt("destroyed"), Material.getMaterial(rs.getInt("type")).toString().toLowerCase().replace('_', ' ')));
}
}
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock PlayerAreaStats] SQL exception", ex);
} finally {
try {
if (rs != null)
rs.close();
if (ps != null)
ps.close();
if (conn != null)
conn.close();
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock PlayerAreaStats] SQL exception on close", ex);
}
}
}
}

View File

@@ -1,126 +1,143 @@
package de.diddiz.LogBlock; package de.diddiz.LogBlock;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.command.CommandSender; import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.selections.CuboidSelection; import com.sk89q.worldedit.bukkit.selections.CuboidSelection;
import com.sk89q.worldedit.bukkit.selections.Selection; import com.sk89q.worldedit.bukkit.selections.Selection;
import de.diddiz.util.BukkitUtils;
import de.diddiz.util.Utils;
public class QueryParams public class QueryParams implements Cloneable
{ {
private static final HashSet<Integer> keywords = new HashSet<Integer>(Arrays.asList("player".hashCode(), "area".hashCode(), "selection".hashCode(), "sel".hashCode(), "block".hashCode(), "type".hashCode(), "sum".hashCode(), "destroyed".hashCode(), "created".hashCode(), "chestaccess".hashCode(), "all".hashCode(), "time".hashCode(), "since".hashCode(), "before".hashCode(), "limit".hashCode(), "world".hashCode(), "asc".hashCode(), "desc".hashCode(), "last".hashCode()));
private final LogBlock logblock; private final LogBlock logblock;
private final List<String> players = new ArrayList<String>(); List<String> players = new ArrayList<String>();
private final List<Integer> types = new ArrayList<Integer>(); List<Integer> types = new ArrayList<Integer>();
private Location loc = null; Location loc = null;
private int radius = -1; int radius = -1;
private Selection sel = null; Selection sel = null;
private int minutes = -1; int minutes = 0;
private SummarizationMode sum = SummarizationMode.NONE;; SummarizationMode sum = SummarizationMode.NONE;
private BlockChangeType bct = BlockChangeType.BOTH; BlockChangeType bct = BlockChangeType.BOTH;
private int limit = 15; int limit = 15;
private World world = null; World world = null;
private Order order = Order.DESC; Order order = Order.DESC;
boolean selectFullBlockData = false;
boolean prepareToolQuery = false;
public QueryParams(LogBlock logblock) { public QueryParams(LogBlock logblock) {
this.logblock = logblock; this.logblock = logblock;
} }
public void merge (QueryParams params) { public QueryParams(LogBlock logblock, CommandSender sender, List<String> args) throws IllegalArgumentException {
loc = params.getLoc(); this.logblock = logblock;
radius = params.getRadius(); parseArgs(sender, args);
sel = params.getSel();
minutes = params.getMinutes();
sum = params.getSummarizationMode();
bct = params.getBlockChangeType();
limit = params.limit;
world = params.getWorld();
order = params.getOrder();
} }
public void parseArgs(CommandSender sender, List<String> args) throws Exception { private void merge(QueryParams params) {
players = params.players;
types = params.types;
loc = params.loc;
radius = params.radius;
sel = params.sel;
if (minutes == 0)
minutes = params.minutes;
sum = params.sum;
bct = params.bct;
limit = params.limit;
world = params.world;
order = params.order;
}
public void parseArgs(CommandSender sender, List<String> args) throws IllegalArgumentException {
if (args == null || args.size() == 0)
throw new IllegalArgumentException("No parameters specified.");
Player player = null; Player player = null;
if (sender instanceof Player) if (sender instanceof Player)
player = (Player)sender; player = (Player)sender;
String name = "Console"; final String name = BukkitUtils.getSenderName(sender);
if (player != null) final Session session;
name = player.getName(); if (!prepareToolQuery)
final Session session = logblock.getSession(name); session = logblock.getSession(name);
if (!args.isEmpty() && args.get(0).equalsIgnoreCase("last") && session.getLastQuery() != null) else
merge(session.getLastQuery()); session = null;
if (player != null && world == null) if (player != null && world == null)
world = player.getWorld(); world = player.getWorld();
for (int i = 0; i < args.size(); i++) { for (int i = 0; i < args.size(); i++) {
final String param = args.get(i).toLowerCase(); final String param = args.get(i).toLowerCase();
final String[] values = getValues(args, i +1); final String[] values = getValues(args, i + 1);
if (values != null) if (param.equals("last")) {
i += values.length; if (session.lastQuery == null)
if (param.equals("player")) { throw new IllegalArgumentException("This is your first command, you can't use last.");
merge(session.lastQuery);
} else if (param.equals("player")) {
if (values == null || values.length < 1) if (values == null || values.length < 1)
throw new Exception("No or wrong count of arguments for '" + param + "'"); throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'");
for (final String playerName : values) { for (final String playerName : values)
if (playerName.length() > 0) if (playerName.length() > 0)
players.add(playerName); players.add(playerName);
} } else if (param.equals("block") || param.equals("type")) {
} else if (param.equals("block")) {
if (values == null || values.length < 1) if (values == null || values.length < 1)
throw new Exception("No or wrong count of arguments for '" + param + "'"); throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'");
for (final String blockName : values) { for (final String blockName : values) {
final Material mat = Material.matchMaterial(blockName); final Material mat = Material.matchMaterial(blockName);
if (mat == null) if (mat == null)
throw new Exception("No material matching: '" + blockName + "'"); throw new IllegalArgumentException("No material matching: '" + blockName + "'");
types.add(mat.getId()); types.add(mat.getId());
} }
} else if (param.equals("area")) { } else if (param.equals("area")) {
if (player == null) if (player == null && !prepareToolQuery)
throw new Exception("You have to ba a player to use area"); throw new IllegalArgumentException("You have to ba a player to use area");
if (values == null) { if (values == null) {
radius = logblock.getConfig().defaultDist; radius = logblock.getConfig().defaultDist;
loc = player.getLocation(); if (!prepareToolQuery)
loc = player.getLocation();
} else { } else {
if (!isInt(values[0])) if (!Utils.isInt(values[0]))
throw new Exception("Not a number: '" + values[0] + "'"); throw new IllegalArgumentException("Not a number: '" + values[0] + "'");
radius = Integer.parseInt(values[0]); radius = Integer.parseInt(values[0]);
loc = player.getLocation(); if (!prepareToolQuery)
loc = player.getLocation();
} }
} else if (param.equals("selection")) { } else if (param.equals("selection") || param.equals("sel")) {
if (player == null) if (player == null)
throw new Exception("You have to ba a player to use selection"); throw new IllegalArgumentException("You have to ba a player to use selection");
final Plugin we = player.getServer().getPluginManager().getPlugin("WorldEdit"); final Plugin we = player.getServer().getPluginManager().getPlugin("WorldEdit");
if (we == null) if (we == null)
throw new Exception("WorldEdit plugin not found"); throw new IllegalArgumentException("WorldEdit plugin not found");
final Selection sel = ((WorldEditPlugin)we).getSelection(player); sel = ((WorldEditPlugin)we).getSelection(player);
if (sel == null) if (sel == null)
throw new Exception("No selection defined"); throw new IllegalArgumentException("No selection defined");
if (!(sel instanceof CuboidSelection)) if (!(sel instanceof CuboidSelection))
throw new Exception("You have to define a cuboid selection"); throw new IllegalArgumentException("You have to define a cuboid selection");
this.sel = sel; world = sel.getWorld();
} else if (param.equals("time")) { } else if (param.equals("time") || param.equals("since")) {
if (values == null) if (values == null)
minutes = logblock.getConfig().defaultTime; minutes = logblock.getConfig().defaultTime;
else { else
if (values.length != 2) minutes = Utils.parseTimeSpec(values);
throw new Exception("Wrong count of arguments for '" + param + "'"); if (minutes == -1)
if (!isInt(values[0])) throw new IllegalArgumentException("Faile to parse time spec for '" + param + "'");
throw new Exception("Not a number: '" + values[0] + "'"); } else if (param.equals("before")) {
minutes = Integer.parseInt(values[0]); if (values == null)
if (values[1].startsWith("h")) minutes = logblock.getConfig().defaultTime * -1;
minutes *= 60; else
else if (values[1].startsWith("d")) minutes = Utils.parseTimeSpec(values) * -1;
minutes *= 60*24; if (minutes == 1)
} throw new IllegalArgumentException("Faile to parse time spec for '" + param + "'");
} else if (param.equals("since")) {
throw new Exception("Since parameter not implemented yet");
} else if (param.equals("sum")) { } else if (param.equals("sum")) {
if (values == null || values.length != 1) if (values == null || values.length != 1)
throw new Exception("No or wrong count of arguments for '" + param + "'"); throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'");
if (values[0].startsWith("p")) if (values[0].startsWith("p"))
sum = SummarizationMode.PLAYERS; sum = SummarizationMode.PLAYERS;
else if (values[0].startsWith("b")) else if (values[0].startsWith("b"))
@@ -128,37 +145,57 @@ public class QueryParams
else if (values[0].startsWith("n")) else if (values[0].startsWith("n"))
sum = SummarizationMode.NONE; sum = SummarizationMode.NONE;
else else
throw new Exception("Wrong summarization mode"); throw new IllegalArgumentException("Wrong summarization mode");
} else if (param.equals("created")) { } else if (param.equals("created"))
bct = BlockChangeType.CREATED; bct = BlockChangeType.CREATED;
} else if (param.equals("destroyed")) { else if (param.equals("destroyed"))
bct = BlockChangeType.DESTROYED; bct = BlockChangeType.DESTROYED;
} else if (param.equals("chestaccess")) { else if (param.equals("chestaccess"))
bct = BlockChangeType.CHESTACCESS; bct = BlockChangeType.CHESTACCESS;
} else if (param.equals("limit")) { else if (param.equals("all"))
bct = BlockChangeType.ALL;
else if (param.equals("limit")) {
if (values.length != 1) if (values.length != 1)
throw new Exception("Wrong count of arguments for '" + param + "'"); throw new IllegalArgumentException("Wrong count of arguments for '" + param + "'");
if (!isInt(values[0])) if (!Utils.isInt(values[0]))
throw new Exception("Not a number: '" + values[0] + "'"); throw new IllegalArgumentException("Not a number: '" + values[0] + "'");
limit = Integer.parseInt(values[0]); limit = Integer.parseInt(values[0]);
} else if (param.equals("world")) { } else if (param.equals("world")) {
if (values.length != 1) if (values.length != 1)
throw new Exception("Wrong count of arguments for '" + param + "'"); throw new IllegalArgumentException("Wrong count of arguments for '" + param + "'");
if (sender.getServer().getWorld(values[0]) == null) if (sender.getServer().getWorld(values[0]) == null)
throw new Exception("There is no world called '" + values[0] + "'"); throw new IllegalArgumentException("There is no world called '" + values[0] + "'");
world = sender.getServer().getWorld(values[0]); world = sender.getServer().getWorld(values[0]);
} else if (param.equals("ASC")) { } else if (param.equals("asc"))
order = Order.ASC; order = Order.ASC;
} else if (param.equals("DESC")) { else if (param.equals("desc"))
order = Order.DESC; order = Order.DESC;
} else else
throw new Exception("Not a valid argument: '" + param + "'"); throw new IllegalArgumentException("Not a valid argument: '" + param + "'");
if (values != null)
i += values.length;
} }
if (world == null) if (types.size() > 0)
throw new Exception("No world specified"); for (final Set<Integer> equivalent : BukkitUtils.getBlockEquivalents()) {
if (!logblock.getConfig().tables.containsKey(world.getName().hashCode())) boolean found = false;
throw new Exception("This world ('" + world.getName() + "') isn't logged"); for (final Integer type : types)
session.setLast(this); if (equivalent.contains(type)) {
found = true;
break;
}
if (found)
for (final Integer type : equivalent)
if (!types.contains(type))
types.add(type);
}
if (!prepareToolQuery) {
if (world == null)
throw new IllegalArgumentException("No world specified");
if (!logblock.getConfig().tables.containsKey(world.getName().hashCode()))
throw new IllegalArgumentException("This world ('" + world.getName() + "') isn't logged");
}
if (session != null)
session.lastQuery = clone();
} }
public void setPlayer(String playerName) { public void setPlayer(String playerName) {
@@ -166,217 +203,185 @@ public class QueryParams
players.add(playerName); players.add(playerName);
} }
public List<String> getPlayers() {
return players;
}
public List<Integer> getTypes() {
return types;
}
public Location getLoc() {
return loc;
}
public int getRadius() {
return radius;
}
public Selection getSel() {
return sel;
}
public int getMinutes() {
return minutes;
}
public int getLimit() {
return limit;
}
public Order getOrder() {
return order;
}
public void setLimit(int limit) {
this.limit = limit;
}
public void setOrder(Order order) {
this.order = order;
}
public SummarizationMode getSummarizationMode() {
return sum;
}
public void setSummarizationMode(SummarizationMode sum) {
this.sum = sum;
}
public void setBlockChangeType(BlockChangeType bct) {
this.bct = bct;
}
public BlockChangeType getBlockChangeType() {
return bct;
}
public World getWorld() {
return world;
}
public String getTable() { public String getTable() {
return logblock.getConfig().tables.get(world.getName().hashCode()); return logblock.getConfig().tables.get(world.getName().hashCode());
} }
public String getTitle() { public String getTitle() {
final StringBuffer buffer = new StringBuffer(); final StringBuilder title = new StringBuilder();
if (!types.isEmpty()) { if (!types.isEmpty()) {
for (int i = 0; i < types.size(); i++) { for (int i = 0; i < types.size(); i++)
buffer.append(getMaterialName(types.get(i)) + ", "); title.append(BukkitUtils.getMaterialName(types.get(i)) + ", ");
} title.deleteCharAt(title.length() - 2);
buffer.deleteCharAt(buffer.length() - 2);
} else } else
buffer.append("Block "); title.append("Block ");
if (bct == BlockChangeType.CREATED) if (bct == BlockChangeType.CREATED)
buffer.append("creations "); title.append("creations ");
else if (bct == BlockChangeType.DESTROYED) else if (bct == BlockChangeType.DESTROYED)
buffer.append("destructions "); title.append("destructions ");
else else
buffer.append("changes "); title.append("changes ");
if (!players.isEmpty()) { if (!players.isEmpty()) {
buffer.append("from player "); title.append("from player ");
for (int i = 0; i < players.size(); i++) { for (int i = 0; i < players.size(); i++)
buffer.append(players.get(i) + ", "); title.append(players.get(i) + ", ");
} title.deleteCharAt(title.length() - 2);
buffer.deleteCharAt(buffer.length() - 2);
} }
if (loc != null && radius >= 0) if (minutes > 0)
buffer.append("within " + radius + " blocks of you:"); title.append("in the last " + minutes + " minutes ");
if (minutes < 0)
title.append("up to " + minutes + " minutes ago ");
if (loc != null && radius > 0)
title.append("within " + radius + " blocks of you ");
if (loc != null && radius == 0)
title.append("at " + loc.getBlockX() + ":" + loc.getBlockY() + ":" + loc.getBlockZ() + " ");
else if (sel != null) else if (sel != null)
buffer.append("in selection:"); title.append("inside selection ");
else title.append("in " + getfriendlyWorldname());
buffer.append("in entire world:"); title.setCharAt(0, String.valueOf(title.charAt(0)).toUpperCase().toCharArray()[0]);
buffer.setCharAt(0,String.valueOf(buffer.charAt(0)).toUpperCase().toCharArray()[0]); return title.toString();
return buffer.toString();
} }
public String getQuery() { public String getOrderBy() {
final StringBuffer where = new StringBuffer(); return "ORDER BY date " + order + ", id " + order + " ";
switch (bct) { }
case ALL:
if (!types.isEmpty()) { public String getLimit() {
where.append('('); if (limit == -1)
for (final int type: types) { return "";
where.append("type = " + type + " OR replaced = " + type + " OR "); return "LIMIT " + limit;
}
public String getWhere() {
return getWhere(bct);
}
public String getWhere(BlockChangeType blockChangeType) {
final StringBuilder where = new StringBuilder("WHERE ");
switch (blockChangeType) {
case ALL:
if (!types.isEmpty()) {
where.append('(');
for (final int type : types)
where.append("type = " + type + " OR replaced = " + type + " OR ");
where.delete(where.length() - 4, where.length() - 1);
where.append(") AND ");
} }
where.delete(where.length() - 4, where.length() - 1); break;
where.append(") AND "); case BOTH:
} where.append("type <> replaced AND ");
break; if (!types.isEmpty()) {
case BOTH: where.append('(');
where.append("type <> replaced AND "); for (final int type : types)
if (!types.isEmpty()) { where.append("type = " + type + " OR replaced = " + type + " OR ");
where.append('('); where.delete(where.length() - 4, where.length());
for (final int type: types) { where.append(") AND ");
where.append("type = " + type + " OR replaced = " + type + " OR ");
} }
where.delete(where.length() - 4, where.length()); break;
where.append(") AND "); case CREATED:
} where.append("type <> replaced AND ");
break; if (!types.isEmpty()) {
case CREATED: where.append('(');
where.append("type <> replaced AND "); for (final int type : types)
if (!types.isEmpty()) { where.append("type = " + type + " OR ");
where.append('('); where.delete(where.length() - 4, where.length());
for (final int type: types) { where.append(") AND ");
where.append("type = " + type + " OR "); } else
} where.append("type > 0 AND ");
where.delete(where.length() - 4, where.length()); break;
where.append(") AND "); case DESTROYED:
} else where.append("type <> replaced AND ");
where.append("type > 0 AND "); if (!types.isEmpty()) {
break; where.append('(');
case DESTROYED: for (final int type : types)
where.append("type <> replaced AND "); where.append("replaced = " + type + " OR ");
if (!types.isEmpty()) { where.delete(where.length() - 4, where.length());
where.append('('); where.append(") AND ");
for (final int type: types) { } else
where.append("replaced = " + type + " OR "); where.append("replaced > 0 AND ");
} break;
where.delete(where.length() - 4, where.length()); case CHESTACCESS:
where.append(") AND "); where.append("type = replaced AND (type = 23 OR type = 54 OR type = 61) AND ");
} else break;
where.append("replaced > 0 AND ");
break;
case CHESTACCESS:
where.append("type = replaced AND (type = 23 OR type = 54 OR type = 61) ");
break;
} }
if (!players.isEmpty() && sum != SummarizationMode.PLAYERS) { if (!players.isEmpty() && sum != SummarizationMode.PLAYERS) {
where.append('('); where.append('(');
for (final String playerName: players) { for (final String playerName : players)
where.append("playername = '" + playerName + "' OR "); where.append("playername = '" + playerName + "' OR ");
}
where.delete(where.length() - 4, where.length()); where.delete(where.length() - 4, where.length());
where.append(") AND "); where.append(") AND ");
} }
if (loc != null && radius >= 0) if (loc != null) {
where.append("x > '" + (loc.getBlockX() - radius) + "' AND x < '" + (loc.getBlockX() + radius) + "' AND z > '" + (loc.getBlockZ() - radius) + "' AND z < '" + (loc.getBlockZ() + radius) + "' AND "); if (radius == 0)
else if (sel != null) where.append("x = '" + loc.getBlockX() + "' AND y = '" + loc.getBlockY() + "' AND z = '" + loc.getBlockZ() + "' AND ");
where.append("x >= '"+ sel.getMinimumPoint().getBlockX() + "' AND x <= '" + sel.getMaximumPoint().getBlockX() + "' AND y >= '" + sel.getMinimumPoint().getBlockY() + "' AND y <= '" + sel.getMaximumPoint().getBlockY() + "' AND z >= '" + sel.getMinimumPoint().getBlockZ() + "' AND z <= '" + sel.getMaximumPoint().getBlockZ() + "' AND "); else if (radius > 0)
if (minutes >= 0) where.append("x > '" + (loc.getBlockX() - radius) + "' AND x < '" + (loc.getBlockX() + radius) + "' AND z > '" + (loc.getBlockZ() - radius) + "' AND z < '" + (loc.getBlockZ() + radius) + "' AND ");
} else if (sel != null)
where.append("x >= '" + sel.getMinimumPoint().getBlockX() + "' AND x <= '" + sel.getMaximumPoint().getBlockX() + "' AND y >= '" + sel.getMinimumPoint().getBlockY() + "' AND y <= '" + sel.getMaximumPoint().getBlockY() + "' AND z >= '" + sel.getMinimumPoint().getBlockZ() + "' AND z <= '" + sel.getMaximumPoint().getBlockZ() + "' AND ");
if (minutes > 0)
where.append("date > date_sub(now(), INTERVAL " + minutes + " MINUTE) AND "); where.append("date > date_sub(now(), INTERVAL " + minutes + " MINUTE) AND ");
where.delete(where.length() - 4, where.length()); if (minutes < 0)
if (sum == SummarizationMode.NONE) { where.append("date < date_sub(now(), INTERVAL " + minutes * -1 + " MINUTE) AND ");
final StringBuffer sql = new StringBuffer("SELECT date, replaced, type, playername FROM `" + getTable() + "` INNER JOIN `lb-players` USING (playerid) "); if (where.length() > 6)
if (bct == BlockChangeType.ALL) where.delete(where.length() - 4, where.length());
sql.append("LEFT JOIN `" + getTable() + "-sign` USING (id) "); else
if (bct == BlockChangeType.ALL || bct == BlockChangeType.CHESTACCESS) where.delete(0, where.length());
sql.append("LEFT JOIN `" + getTable() + "-chest` USING (id) "); return where.toString();
sql.append("WHERE " + where + "ORDER BY date " + order + ", id " + order + " ");
if (limit > 0)
sql.append("LIMIT " + limit);
return sql.toString();
} else if (sum == SummarizationMode.TYPES)
return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(type) AS created, 0 AS destroyed FROM `" + getTable() + "` INNER JOIN `lb-players` USING (playerid) WHERE " + where + "GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(replaced) AS destroyed FROM `" + getTable() + "` INNER JOIN `lb-players` USING (playerid) WHERE " + where + "GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) DESC LIMIT 15";
else {
return "SELECT playername, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(type) AS created, 0 AS destroyed FROM `" + getTable() + "` WHERE " + where + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(replaced) AS destroyed FROM `" + getTable() + "` WHERE " + where + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) DESC LIMIT 15";
}
} }
private String getMaterialName(int type) { public String getQuery() {
return Material.getMaterial(type).toString().toLowerCase().replace('_', ' '); if (sum == SummarizationMode.NONE) {
final StringBuilder select = new StringBuilder("SELECT ");
final StringBuilder from = new StringBuilder("FROM `" + getTable() + "` ");
if (selectFullBlockData)
select.append("replaced, type, data, x, y, z ");
else
select.append("date, replaced, type, playername");
if (!selectFullBlockData || players.size() > 0)
from.append("INNER JOIN `lb-players` USING (playerid) ");
if (types.size() == 0 || types.contains(63) || types.contains(68)) {
select.append(", signtext");
from.append("LEFT JOIN `" + getTable() + "-sign` USING (id) ");
}
if (types.size() == 0 || types.contains(23) || types.contains(54) || types.contains(61)) {
select.append(", itemtype, itemamount, itemdata");
from.append("LEFT JOIN `" + getTable() + "-chest` USING (id) ");
}
return select.toString() + " " + from.toString() + getWhere() + getOrderBy() + getLimit();
} else if (sum == SummarizationMode.TYPES)
return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(type) AS created, 0 AS destroyed FROM `" + getTable() + "` INNER JOIN `lb-players` USING (playerid) " + getWhere() + "AND type > 0 GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(replaced) AS destroyed FROM `" + getTable() + "` INNER JOIN `lb-players` USING (playerid) " + getWhere() + "AND replaced > 0 GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit();
else
return "SELECT playername, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(type) AS created, 0 AS destroyed FROM `" + getTable() + "` " + getWhere() + "AND type > 0 GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(replaced) AS destroyed FROM `" + getTable() + "` " + getWhere() + "AND replaced > 0 GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit();
} }
private String[] getValues(List<String> args, int offset) { private String[] getValues(List<String> args, int offset) {
int i; int i;
for (i = offset; i < args.size(); i++) { for (i = offset; i < args.size(); i++)
if (isKeyWord(args.get(i))) if (isKeyWord(args.get(i)))
break; break;
}
if (i == offset) if (i == offset)
return null; return null;
else { final String[] values = new String[i - offset];
final String[] values = new String[i - offset]; for (int j = offset; j < i; j++)
System.arraycopy(args.toArray(), offset, values, 0, i - offset); values[j - offset] = args.get(j).replace("\"", "");
return values; return values;
}
} }
private boolean isInt(String str) { private String getfriendlyWorldname() {
String worldName = world.getName();
worldName = worldName.substring(worldName.lastIndexOf('/') + 1);
return worldName.substring(worldName.lastIndexOf('\\') + 1);
}
protected QueryParams clone() {
try { try {
Integer.parseInt(str); return (QueryParams)super.clone();
return true; } catch (final CloneNotSupportedException ex) {}
} catch (final Exception ex) { return null;
return false;
}
} }
public static boolean isKeyWord(String param) { static boolean isKeyWord(String param) {
final String key = new String(param).toLowerCase(); if (keywords.contains(param.toLowerCase().hashCode()))
if (key.equals("player") || key.equals("area") || key.equals("selection") || key.equals("block") || key.equals("sum") || key.equals("destroyed") || key.equals("created") || key.equals("time") || key.equals("since") || key.equals("limit") || key.equals("world") || key.equals("asc") || key.equals("desc"))
return true; return true;
return false; return false;
} }

View File

@@ -1,212 +0,0 @@
package de.diddiz.LogBlock;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.ChatColor;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;
import com.sk89q.worldedit.bukkit.selections.Selection;
public class Rollback implements Runnable
{
private final Logger log;
private final LogBlock logblock;
private final Config config;
private final Player player;
private final Connection conn;
private final String query;
private final boolean redo;
Rollback(LogBlock logblock, Player player, String name, int radius, Selection sel, int minutes, boolean redo) {
this.logblock = logblock;
this.player = player;
this.redo = redo;
log = logblock.getServer().getLogger();
conn = logblock.getConnection();
config = logblock.getConfig();
final StringBuffer sql = new StringBuffer();
if (!redo)
sql.append("SELECT replaced, type, data, x, y, z ");
else
sql.append("SELECT type AS replaced, replaced AS type, data, x, y, z ");
sql.append("FROM `" + logblock.getConfig().tables.get(player.getWorld().getName().hashCode()) + "` INNER JOIN `lb-players` USING (playerid) WHERE (type <> replaced OR (type = 0 AND replaced = 0)) AND ");
if (name != null)
sql.append("playername = '" + name + "' AND ");
if (radius != -1)
sql.append("x > '" + (player.getLocation().getBlockX() - radius) + "' AND x < '" + (player.getLocation().getBlockX() + radius) + "' AND z > '" + (player.getLocation().getBlockZ() - radius) + "' AND z < '" + (player.getLocation().getBlockZ() + radius) + "' AND ");
if (sel != null)
sql.append("x >= '"+ Math.min(sel.getMinimumPoint().getBlockX(), sel.getMaximumPoint().getBlockX()) + "' AND x <= '" + Math.max(sel.getMinimumPoint().getBlockX(), sel.getMaximumPoint().getBlockX()) + "' AND y >= '" + Math.min(sel.getMinimumPoint().getBlockY(), sel.getMaximumPoint().getBlockY()) + "' AND y <= '" + Math.max(sel.getMinimumPoint().getBlockY(), sel.getMaximumPoint().getBlockY()) + "' AND z >= '" + Math.min(sel.getMinimumPoint().getBlockZ(), sel.getMaximumPoint().getBlockZ()) + "' AND z <= '" + Math.max(sel.getMinimumPoint().getBlockZ(), sel.getMaximumPoint().getBlockZ()) + "' AND ");
if (minutes >= 0)
sql.append("date > date_sub(now(), INTERVAL " + minutes + " MINUTE) AND ");
sql.delete(sql.length() - 5, sql.length() - 1);
if (!redo)
sql.append("ORDER BY date DESC, id DESC");
else
sql.append("ORDER BY date ASC, id ASC");
query = sql.toString();
}
@Override
public void run() {
ResultSet rs = null;
final LinkedBlockingQueue<Edit> edits = new LinkedBlockingQueue<Edit>();
edits.clear();
try {
if (!config.tables.containsKey(player.getWorld().getName().hashCode())) {
player.sendMessage(ChatColor.RED + "This world isn't logged!");
return;
}
rs = conn.createStatement().executeQuery(query);
while (rs.next()) {
final Edit e = new Edit(rs.getInt("type"), rs.getInt("replaced"), rs.getByte("data"), rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), player.getWorld());
edits.offer(e);
}
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock Rollback] SQL exception", ex);
player.sendMessage(ChatColor.RED + "Error, check server logs.");
return;
} finally {
try {
if (rs != null)
rs.close();
if (conn != null)
conn.close();
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock Rollback] SQL exception on close", ex);
player.sendMessage(ChatColor.RED + "Error, check server logs.");
return;
}
}
final int changes = edits.size();
player.sendMessage(ChatColor.GREEN + "" + changes + " Changes found.");
final PerformRollback perform = new PerformRollback(edits, this);
final long start = System.currentTimeMillis();
final int taskID = logblock.getServer().getScheduler().scheduleSyncRepeatingTask(logblock, perform, 0, 1);
if (taskID == -1) {
player.sendMessage(ChatColor.RED + "Failed to schedule rollback task");
return;
}
synchronized (this) {
try {
this.wait();
} catch (final InterruptedException e) {
log.severe("[LogBlock Rollback] Interrupted");
}
}
logblock.getServer().getScheduler().cancelTask(taskID);
if (!redo) {
player.sendMessage(ChatColor.GREEN + "Rollback finished successfully");
player.sendMessage(ChatColor.GREEN + "Undid " + perform.successes + " of " + changes + " changes (" + perform.errors + " errors, " + perform.blacklisteds + " blacklist collisions)");
} else {
player.sendMessage(ChatColor.GREEN + "Redo finished successfully");
player.sendMessage(ChatColor.GREEN + "Redid " + perform.successes + " of " + changes + " changes (" + perform.errors + " errors, " + perform.blacklisteds + " blacklist collisions)");
}
player.sendMessage(ChatColor.GREEN + "Took: " + (System.currentTimeMillis() - start) + "ms");
}
private class PerformRollback implements Runnable
{
private final LinkedBlockingQueue<Edit> edits;
private final Rollback rollback;
int successes = 0;
int errors = 0;
int blacklisteds = 0;
PerformRollback(LinkedBlockingQueue<Edit> edits, Rollback rollback) {
this.edits = edits;
this.rollback = rollback;
}
@Override
public void run() {
int counter = 0;
while (!edits.isEmpty() && counter < 1000)
{
switch (edits.poll().perform()) {
case SUCCESS:
successes++;
break;
case ERROR:
errors++;
break;
case BLACKLISTED:
blacklisteds++;
break;
}
counter++;
}
if (edits.isEmpty()) {
synchronized (rollback) {
rollback.notify();
}
}
}
}
private enum PerformResult {
ERROR, SUCCESS, BLACKLISTED, NO_ACTION
}
private class Edit
{
final int type, replaced;
final int x, y, z;
final byte data;
final World world;
Edit(int type, int replaced, byte data, int x, int y, int z, World world) {
this.type = type;
this.replaced = replaced;
this.data = data;
this.x = x;
this.y = y;
this.z = z;
this.world = world;
}
private PerformResult perform() {
if (config.dontRollback.contains(replaced))
return PerformResult.BLACKLISTED;
try {
final Block block = world.getBlockAt(x, y, z);
if (!world.isChunkLoaded(block.getChunk()))
world.loadChunk(block.getChunk());
if (equalsType(block.getTypeId(), type) || config.replaceAnyway.contains(block.getTypeId()) || type == 0 && replaced == 0) {
if (block.setTypeIdAndData(replaced, data, false))
return PerformResult.SUCCESS;
else
return PerformResult.ERROR;
} else
return PerformResult.NO_ACTION;
} catch (final Exception ex) {
log.severe("[LogBlock Rollback] " + ex.toString());
return PerformResult.ERROR;
}
}
private boolean equalsType(int type1, int type2) {
if (type1 == type2)
return true;
if ((type1 == 2 || type1 == 3) && (type2 == 2 || type2 == 3))
return true;
if ((type1 == 8 || type1 == 9) && (type2 == 8 || type2 == 9))
return true;
if ((type1 == 10 || type1 == 11) && (type2 == 10 || type2 == 11))
return true;
if ((type1 == 73 || type1 == 74) && (type2 == 73 || type2 == 74))
return true;
if ((type1 == 75 || type1 == 76) && (type2 == 75 || type2 == 76))
return true;
if ((type1 == 93 || type1 == 94) && (type2 == 93 || type2 == 94))
return true;
return false;
}
}
}

View File

@@ -1,13 +1,15 @@
package de.diddiz.LogBlock; package de.diddiz.LogBlock;
public class Session { public class Session
private QueryParams last = null; {
public QueryParams lastQuery = null;
public QueryParams toolQuery;
public QueryParams toolBlockQuery;
public boolean toolEnabled = true;
public boolean toolBlockEnabled = true;
public QueryParams getLastQuery() { Session(LogBlock logblock) {
return last; toolQuery = logblock.getConfig().toolQuery.clone();
} toolBlockQuery = logblock.getConfig().toolBlockQuery.clone();
public void setLast(QueryParams params) {
last = params;
} }
} }

View File

@@ -2,16 +2,29 @@ package de.diddiz.LogBlock;
import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger; import java.util.logging.Logger;
import org.bukkit.World; import org.bukkit.World;
import org.bukkit.block.Block; import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.ContainerBlock;
import org.bukkit.block.Sign;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
import de.diddiz.util.BukkitUtils;
public class WorldEditor implements Runnable public class WorldEditor implements Runnable
{ {
public static class WorldEditorException extends Exception
{
private static final long serialVersionUID = 7509084196124728986L;
public WorldEditorException(String msg) {
super(msg);
}
}
private final Logger log; private final Logger log;
private final LogBlock logblock; private final LogBlock logblock;
private final Config config; private final Config config;
private final Object caller;
private final LinkedBlockingQueue<Edit> edits = new LinkedBlockingQueue<Edit>(); private final LinkedBlockingQueue<Edit> edits = new LinkedBlockingQueue<Edit>();
private final World world; private final World world;
private int taskID; private int taskID;
@@ -19,101 +32,91 @@ public class WorldEditor implements Runnable
private int errors = 0; private int errors = 0;
private int blacklistCollisions = 0; private int blacklistCollisions = 0;
WorldEditor(LogBlock logblock, Object caller, World world) { WorldEditor(LogBlock logblock, World world) {
log = logblock.getServer().getLogger(); log = logblock.getServer().getLogger();
this.logblock = logblock; this.logblock = logblock;
config = logblock.getConfig(); config = logblock.getConfig();
this.caller = caller;
this.world = world; this.world = world;
} }
public int getSize() { int getSize() {
return edits.size(); return edits.size();
} }
public int getSuccesses() { int getSuccesses() {
return successes; return successes;
} }
public int getErrors() { int getErrors() {
return errors; return errors;
} }
public int getBlacklistCollisions() { int getBlacklistCollisions() {
return blacklistCollisions; return blacklistCollisions;
} }
public void queueBlockChange(int type, int replaced, byte data, int x, int y, int z) { void queueBlockChange(int type, int replaced, byte data, int x, int y, int z, String signtext, short itemType, short itemAmount, byte itemData) {
edits.add(new Edit(type, replaced, data, x, y, z)); edits.add(new Edit(type, replaced, data, x, y, z, signtext, itemType, itemAmount, itemData));
} }
public boolean start() { synchronized void start() throws WorldEditorException {
taskID = logblock.getServer().getScheduler().scheduleSyncRepeatingTask(logblock, this, 0, 1); taskID = logblock.getServer().getScheduler().scheduleSyncRepeatingTask(logblock, this, 0, 1);
if (taskID == -1) if (taskID == -1)
return false; throw new WorldEditorException("Failed to schedule task");
return true; try {
this.wait();
} catch (final InterruptedException ex) {
throw new WorldEditorException("Interrupted");
}
} }
@Override @Override
public void run() { public synchronized void run() {
int counter = 0; int counter = 0;
while (!edits.isEmpty() && counter < 1000) { while (!edits.isEmpty() && counter < 1000) {
switch (edits.poll().perform()) { switch (edits.poll().perform()) {
case SUCCESS: case SUCCESS:
successes++; successes++;
break; break;
case ERROR: case ERROR:
errors++; errors++;
break; break;
case BLACKLISTED: case BLACKLISTED:
blacklistCollisions++; blacklistCollisions++;
break; break;
} }
counter++; counter++;
} }
if (edits.isEmpty()) { if (edits.isEmpty()) {
logblock.getServer().getScheduler().cancelTask(taskID); logblock.getServer().getScheduler().cancelTask(taskID);
synchronized (caller) { notify();
caller.notify();
}
} }
} }
private boolean equalsType(int type1, int type2) { private static enum PerformResult {
if (type1 == type2)
return true;
if ((type1 == 2 || type1 == 3) && (type2 == 2 || type2 == 3))
return true;
if ((type1 == 8 || type1 == 9) && (type2 == 8 || type2 == 9))
return true;
if ((type1 == 10 || type1 == 11) && (type2 == 10 || type2 == 11))
return true;
if ((type1 == 73 || type1 == 74) && (type2 == 73 || type2 == 74))
return true;
if ((type1 == 75 || type1 == 76) && (type2 == 75 || type2 == 76))
return true;
if ((type1 == 93 || type1 == 94) && (type2 == 93 || type2 == 94))
return true;
return false;
}
private enum PerformResult {
ERROR, SUCCESS, BLACKLISTED, NO_ACTION ERROR, SUCCESS, BLACKLISTED, NO_ACTION
} }
private class Edit private class Edit
{ {
final int type, replaced; private final int type, replaced;
final int x, y, z; private final int x, y, z;
final byte data; private final byte data;
private final String signtext;
public final short itemType, itemAmount;
public final byte itemData;
Edit(int type, int replaced, byte data, int x, int y, int z) { Edit(int type, int replaced, byte data, int x, int y, int z, String signtext, short itemType, short itemAmount, byte itemData) {
this.type = type; this.type = type;
this.replaced = replaced; this.replaced = replaced;
this.data = data; this.data = data;
this.x = x; this.x = x;
this.y = y; this.y = y;
this.z = z; this.z = z;
this.signtext = signtext;
this.itemType = itemType;
this.itemAmount = itemAmount;
this.itemData = itemData;
} }
private PerformResult perform() { private PerformResult perform() {
@@ -121,19 +124,50 @@ public class WorldEditor implements Runnable
return PerformResult.BLACKLISTED; return PerformResult.BLACKLISTED;
try { try {
final Block block = world.getBlockAt(x, y, z); final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
if (!world.isChunkLoaded(block.getChunk())) if (!world.isChunkLoaded(block.getChunk()))
world.loadChunk(block.getChunk()); world.loadChunk(block.getChunk());
if (equalsType(block.getTypeId(), type) || config.replaceAnyway.contains(block.getTypeId()) || type == 0 && replaced == 0) { if (type == replaced)
if (block.setTypeIdAndData(replaced, data, false)) if (type == 0) {
return PerformResult.SUCCESS; if (block.setTypeId(0))
else return PerformResult.SUCCESS;
return PerformResult.ERROR; return PerformResult.ERROR;
} else } else if (type == 23 || type == 54 || type == 61) {
if (!(state instanceof ContainerBlock))
return PerformResult.NO_ACTION;
final Inventory inv = ((ContainerBlock)block.getState()).getInventory();
if (itemType != 0)
if (itemAmount > 0)
inv.removeItem(new ItemStack(itemType, itemAmount, (short)0, itemData));
else if (itemAmount < 0)
inv.addItem(new ItemStack(itemType, itemAmount * -1, (short)0, itemData));
if (!state.update())
return PerformResult.ERROR;
return PerformResult.SUCCESS;
} else
return PerformResult.NO_ACTION;
if (!(BukkitUtils.equalTypes(block.getTypeId(), type) || config.replaceAnyway.contains(block.getTypeId())))
return PerformResult.NO_ACTION; return PerformResult.NO_ACTION;
if (state instanceof ContainerBlock) {
((ContainerBlock)state).getInventory().clear();
state.update();
}
if (!block.setTypeIdAndData(replaced, data, true))
return PerformResult.ERROR;
final int curtype = block.getTypeId();
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]);
if (!sign.update())
return PerformResult.ERROR;
}
return PerformResult.SUCCESS;
} catch (final Exception ex) { } catch (final Exception ex) {
log.severe("[LogBlock Rollback] " + ex.toString()); log.severe("[LogBlock Rollback] " + ex.toString());
return PerformResult.ERROR; return PerformResult.ERROR;
} }
} }
} }
} }

View File

@@ -1,100 +0,0 @@
package de.diddiz.LogBlock;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.entity.Player;
public class WriteLogFile implements Runnable
{
private final Logger log;
private final Connection conn;
private final Player player;
private final String name;
private final String table;
WriteLogFile(LogBlock logblock, Player player, String name) {
this.player = player;
this.name = name;
log = logblock.getServer().getLogger();
conn = logblock.getConnection();
table = logblock.getConfig().tables.get(player.getWorld().getName().hashCode());
}
@Override
public void run() {
PreparedStatement ps = null;
ResultSet rs = null;
final SimpleDateFormat formatter = new SimpleDateFormat("MM-dd HH:mm:ss");
final String newline = System.getProperty("line.separator");
String msg;
try {
if (conn == null) {
player.sendMessage(ChatColor.RED + "Failed to create database connection");
return;
}
if (table == null) {
player.sendMessage(ChatColor.RED + "This world isn't logged");
return;
}
conn.setAutoCommit(false);
ps = conn.prepareStatement("SELECT * FROM `" + table + "` LEFT JOIN `" + table + "-sign` USING (id) INNER JOIN `lb-players` USING (playerid) WHERE playername = ? ORDER BY date ASC");
ps.setString(1, name);
rs = ps.executeQuery();
final File file = new File ("plugins/LogBlock/log/" + name + ".log");
file.getParentFile().mkdirs();
final FileWriter writer = new FileWriter(file);
player.sendMessage(ChatColor.GREEN + "Creating " + file.getName());
while (rs.next()) {
msg = formatter.format(rs.getTimestamp("date")) + " " + rs.getString("playername") + " ";
final int type = rs.getInt("type");
final int replaced = rs.getInt("replaced");
if ((type == 63 || type == 68) && rs.getString("signtext") != null)
msg += "created " + rs.getString("signtext");
else if (type == replaced) {
if (type == 23 || type == 54 || type == 61)
msg += "looked inside " + getMaterialName(type);
} else if (type == 0)
msg += "destroyed " + getMaterialName(replaced);
else if (replaced == 0)
msg += "created " + getMaterialName(type);
else
msg += "replaced " + getMaterialName(replaced) + " with " + getMaterialName(type);
writer.write(msg + newline);
}
writer.close();
player.sendMessage(ChatColor.GREEN + "Done");
} catch (final SQLException ex) {
player.sendMessage(ChatColor.RED + "SQL exception");
log.log(Level.SEVERE, "[LogBlock WriteLogFile] SQL exception", ex);
} catch (final IOException ex) {
player.sendMessage(ChatColor.RED + "IO exception");
log.log(Level.SEVERE, "[LogBlock WriteLogFile] IO exception", ex);
} finally {
try {
if (rs != null)
rs.close();
if (ps != null)
ps.close();
if (conn != null)
conn.close();
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock BlockStats] SQL exception on close", ex);
}
}
}
private String getMaterialName(int type) {
return Material.getMaterial(type).toString().toLowerCase().replace('_', ' ');
}
}

View File

@@ -0,0 +1,163 @@
package de.diddiz.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Set;
import org.bukkit.ChatColor;
import org.bukkit.Material;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public class BukkitUtils
{
private static class ItemStackComparator implements Comparator<ItemStack>
{
@Override
public int compare(ItemStack a, ItemStack b) {
final int aType = a.getTypeId(), bType = b.getTypeId();
if (aType < bType)
return -1;
if (aType > bType)
return 1;
final byte aData = rawData(a), bData = rawData(b);
if (aData < bData)
return -1;
if (aData > bData)
return 1;
return 0;
}
}
private final static Set<Set<Integer>> blockEquivalents;
static {
blockEquivalents = new HashSet<Set<Integer>>(7);
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(2, 3, 60)));
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(8, 9, 79)));
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(10, 11)));
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(61, 62)));
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(73, 74)));
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(75, 76)));
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(93, 94)));
}
public static ItemStack[] compareInventories(ItemStack[] items1, ItemStack[] items2) {
final ItemStackComparator comperator = new ItemStackComparator();
final ArrayList<ItemStack> diff = new ArrayList<ItemStack>();
int c1 = 0, c2 = 0;
while (c1 < items1.length || c2 < items2.length) {
if (c1 >= items1.length) {
diff.add(items2[c2]);
c2++;
continue;
}
if (c2 >= items2.length) {
items1[c1].setAmount(items1[c1].getAmount() * -1);
diff.add(items1[c1]);
c1++;
continue;
}
final int comp = comperator.compare(items1[c1], items2[c2]);
System.out.print("Comparing: " + items1[c1] + " & " + items2[c2] + " = " + comp);
if (comp < 0) {
items1[c1].setAmount(items1[c1].getAmount() * -1);
diff.add(items1[c1]);
c1++;
} else if (comp > 0) {
diff.add(items2[c2]);
c2++;
} else {
final int amount = items1[c1].getAmount() - items2[c2].getAmount();
if (amount != 0) {
items1[c1].setAmount(amount);
diff.add(items1[c1]);
}
c1++;
c2++;
}
}
return diff.toArray(new ItemStack[diff.size()]);
}
public static ItemStack[] compressInventory(ItemStack[] items) {
final ArrayList<ItemStack> compressed = new ArrayList<ItemStack>();
for (final ItemStack item : items)
if (item != null) {
final int type = item.getTypeId();
final byte data = rawData(item);
boolean found = false;
for (final ItemStack item2 : compressed)
if (type == item2.getTypeId() && data == rawData(item2)) {
item2.setAmount(item2.getAmount() + item.getAmount());
found = true;
break;
}
if (!found)
compressed.add(new ItemStack(type, item.getAmount(), (short)0, data));
}
Collections.sort(compressed, new ItemStackComparator());
return compressed.toArray(new ItemStack[compressed.size()]);
}
public static boolean equalTypes(int type1, int type2) {
if (type1 == type2)
return true;
for (final Set<Integer> equivalent : blockEquivalents)
if (equivalent.contains(type1) && equivalent.contains(type2))
return true;
return false;
}
public static Set<Set<Integer>> getBlockEquivalents() {
return blockEquivalents;
}
public static String getEntityName(Entity entity) {
if (entity instanceof Player)
return ((Player)entity).getName();
if (entity instanceof TNTPrimed)
return "TNT";
return entity.getClass().getSimpleName().substring(5);
}
public static String getMaterialName(int type) {
return Material.getMaterial(type).toString().replace('_', ' ').toLowerCase();
}
public static String getSenderName(CommandSender sender) {
if (sender instanceof Player)
return ((Player)sender).getName();
if (sender instanceof ConsoleCommandSender)
return "console";
return sender.getClass().getSimpleName();
}
public static void giveTool(Player player, int type) {
final Inventory inv = player.getInventory();
if (inv.contains(type))
player.sendMessage(ChatColor.RED + "You have alredy a " + getMaterialName(type));
else {
final int free = inv.firstEmpty();
if (free >= 0) {
inv.setItem(free, player.getItemInHand());
player.setItemInHand(new ItemStack(type, 1));
player.sendMessage(ChatColor.GREEN + "Here's your " + getMaterialName(type));
} else
player.sendMessage(ChatColor.RED + "You have no empty slot in your inventory");
}
}
public static byte rawData(ItemStack item) {
if (item.getData() == null)
return 0;
return item.getData().getData();
}
}

View File

@@ -1,5 +1,6 @@
package de.diddiz.util; package de.diddiz.util;
import java.io.Closeable;
import java.sql.Array; import java.sql.Array;
import java.sql.Blob; import java.sql.Blob;
import java.sql.CallableStatement; import java.sql.CallableStatement;
@@ -21,12 +22,13 @@ import java.util.Map;
import java.util.Properties; import java.util.Properties;
import java.util.Vector; import java.util.Vector;
public class ConnectionPool { public class ConnectionPool implements Closeable
{
private final static int poolsize = 10;
private final static long timeToLive = 300000;
private final Vector<JDCConnection> connections; private final Vector<JDCConnection> connections;
private final String url, user, password;
private final long timeout = 60000;
private final ConnectionReaper reaper; private final ConnectionReaper reaper;
private final int poolsize = 10; private final String url, user, password;
public ConnectionPool(String url, String user, String password) throws ClassNotFoundException { public ConnectionPool(String url, String user, String password) throws ClassNotFoundException {
Class.forName("com.mysql.jdbc.Driver"); Class.forName("com.mysql.jdbc.Driver");
@@ -45,10 +47,8 @@ public class ConnectionPool {
if (conn.lease()) { if (conn.lease()) {
if (conn.isValid()) if (conn.isValid())
return conn; return conn;
else { connections.remove(conn);
connections.remove(conn); conn.terminate();
conn.terminate();
}
} }
} }
conn = new JDCConnection(DriverManager.getConnection(url, user, password)); conn = new JDCConnection(DriverManager.getConnection(url, user, password));
@@ -62,13 +62,14 @@ public class ConnectionPool {
} }
private synchronized void reapConnections() { private synchronized void reapConnections() {
final long stale = System.currentTimeMillis() - timeout; final long stale = System.currentTimeMillis() - timeToLive;
for (final JDCConnection conn : connections) for (final JDCConnection conn : connections)
if (conn.inUse() && stale > conn.getLastUse() && !conn.isValid()) if (conn.inUse() && stale > conn.getLastUse() && !conn.isValid())
connections.remove(conn); connections.remove(conn);
} }
public synchronized void closeConnections() { @Override
public synchronized void close() {
final Enumeration<JDCConnection> conns = connections.elements(); final Enumeration<JDCConnection> conns = connections.elements();
while (conns.hasMoreElements()) { while (conns.hasMoreElements()) {
final JDCConnection conn = conns.nextElement(); final JDCConnection conn = conns.nextElement();
@@ -102,28 +103,9 @@ public class ConnectionPool {
timestamp = 0; timestamp = 0;
} }
public void terminate() { @Override
try { public void clearWarnings() throws SQLException {
conn.close(); conn.clearWarnings();
} catch (final SQLException ex) {}
}
public synchronized boolean lease() {
if (inuse)
return false;
else {
inuse = true;
timestamp = System.currentTimeMillis();
return true;
}
}
public boolean inUse() {
return inuse;
}
public long getLastUse() {
return timestamp;
} }
@Override @Override
@@ -131,103 +113,18 @@ public class ConnectionPool {
inuse = false; inuse = false;
try { try {
if (!conn.getAutoCommit()) if (!conn.getAutoCommit())
conn.setAutoCommit(true); conn.setAutoCommit(true);
} catch (SQLException ex) { } catch (final SQLException ex) {
connections.remove(conn); connections.remove(conn);
terminate(); terminate();
} }
} }
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return conn.prepareStatement(sql);
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
return conn.prepareCall(sql);
}
@Override
public Statement createStatement() throws SQLException {
return conn.createStatement();
}
@Override
public String nativeSQL(String sql) throws SQLException {
return conn.nativeSQL(sql);
}
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
conn.setAutoCommit(autoCommit);
}
@Override
public boolean getAutoCommit() throws SQLException {
return conn.getAutoCommit();
}
@Override @Override
public void commit() throws SQLException { public void commit() throws SQLException {
conn.commit(); conn.commit();
} }
@Override
public void rollback() throws SQLException {
conn.rollback();
}
@Override
public boolean isClosed() throws SQLException {
return conn.isClosed();
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
return conn.getMetaData();
}
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
conn.setReadOnly(readOnly);
}
@Override
public boolean isReadOnly() throws SQLException {
return conn.isReadOnly();
}
@Override
public void setCatalog(String catalog) throws SQLException {
conn.setCatalog(catalog);
}
@Override
public String getCatalog() throws SQLException {
return conn.getCatalog();
}
@Override
public void setTransactionIsolation(int level) throws SQLException {
conn.setTransactionIsolation(level);
}
@Override
public int getTransactionIsolation() throws SQLException {
return conn.getTransactionIsolation();
}
@Override
public SQLWarning getWarnings() throws SQLException {
return conn.getWarnings();
}
@Override
public void clearWarnings() throws SQLException {
conn.clearWarnings();
}
@Override @Override
public Array createArrayOf(String typeName, Object[] elements) throws SQLException { public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
return conn.createArrayOf(typeName, elements); return conn.createArrayOf(typeName, elements);
@@ -253,6 +150,11 @@ public class ConnectionPool {
return conn.createSQLXML(); return conn.createSQLXML();
} }
@Override
public Statement createStatement() throws SQLException {
return conn.createStatement();
}
@Override @Override
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.createStatement(resultSetType, resultSetConcurrency); return conn.createStatement(resultSetType, resultSetConcurrency);
@@ -268,6 +170,16 @@ public class ConnectionPool {
return conn.createStruct(typeName, attributes); return conn.createStruct(typeName, attributes);
} }
@Override
public boolean getAutoCommit() throws SQLException {
return conn.getAutoCommit();
}
@Override
public String getCatalog() throws SQLException {
return conn.getCatalog();
}
@Override @Override
public Properties getClientInfo() throws SQLException { public Properties getClientInfo() throws SQLException {
return conn.getClientInfo(); return conn.getClientInfo();
@@ -283,11 +195,44 @@ public class ConnectionPool {
return conn.getHoldability(); return conn.getHoldability();
} }
public long getLastUse() {
return timestamp;
}
@Override
public DatabaseMetaData getMetaData() throws SQLException {
return conn.getMetaData();
}
@Override
public int getTransactionIsolation() throws SQLException {
return conn.getTransactionIsolation();
}
@Override @Override
public Map<String, Class<?>> getTypeMap() throws SQLException { public Map<String, Class<?>> getTypeMap() throws SQLException {
return conn.getTypeMap(); return conn.getTypeMap();
} }
@Override
public SQLWarning getWarnings() throws SQLException {
return conn.getWarnings();
}
public boolean inUse() {
return inuse;
}
@Override
public boolean isClosed() throws SQLException {
return conn.isClosed();
}
@Override
public boolean isReadOnly() throws SQLException {
return conn.isReadOnly();
}
public boolean isValid() { public boolean isValid() {
try { try {
return conn.isValid(1); return conn.isValid(1);
@@ -301,6 +246,29 @@ public class ConnectionPool {
return conn.isValid(timeout); return conn.isValid(timeout);
} }
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return conn.isWrapperFor(iface);
}
public synchronized boolean lease() {
if (inuse)
return false;
inuse = true;
timestamp = System.currentTimeMillis();
return true;
}
@Override
public String nativeSQL(String sql) throws SQLException {
return conn.nativeSQL(sql);
}
@Override
public CallableStatement prepareCall(String sql) throws SQLException {
return conn.prepareCall(sql);
}
@Override @Override
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.prepareCall(sql, resultSetType, resultSetConcurrency); return conn.prepareCall(sql, resultSetType, resultSetConcurrency);
@@ -311,21 +279,16 @@ public class ConnectionPool {
return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability); return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
} }
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return conn.prepareStatement(sql);
}
@Override @Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
return conn.prepareStatement(sql, autoGeneratedKeys); return conn.prepareStatement(sql, autoGeneratedKeys);
} }
@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
return conn.prepareStatement(sql, columnIndexes);
}
@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
return conn.prepareStatement(sql, columnNames);
}
@Override @Override
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.prepareStatement(sql, resultSetType, resultSetConcurrency); return conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
@@ -336,16 +299,41 @@ public class ConnectionPool {
return conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability); return conn.prepareStatement(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
} }
@Override
public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException {
return conn.prepareStatement(sql, columnIndexes);
}
@Override
public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException {
return conn.prepareStatement(sql, columnNames);
}
@Override @Override
public void releaseSavepoint(Savepoint savepoint) throws SQLException { public void releaseSavepoint(Savepoint savepoint) throws SQLException {
conn.releaseSavepoint(savepoint); conn.releaseSavepoint(savepoint);
} }
@Override
public void rollback() throws SQLException {
conn.rollback();
}
@Override @Override
public void rollback(Savepoint savepoint) throws SQLException { public void rollback(Savepoint savepoint) throws SQLException {
conn.rollback(savepoint); conn.rollback(savepoint);
} }
@Override
public void setAutoCommit(boolean autoCommit) throws SQLException {
conn.setAutoCommit(autoCommit);
}
@Override
public void setCatalog(String catalog) throws SQLException {
conn.setCatalog(catalog);
}
@Override @Override
public void setClientInfo(Properties properties) throws SQLClientInfoException { public void setClientInfo(Properties properties) throws SQLClientInfoException {
conn.setClientInfo(properties); conn.setClientInfo(properties);
@@ -361,6 +349,11 @@ public class ConnectionPool {
conn.setHoldability(holdability); conn.setHoldability(holdability);
} }
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
conn.setReadOnly(readOnly);
}
@Override @Override
public Savepoint setSavepoint() throws SQLException { public Savepoint setSavepoint() throws SQLException {
return conn.setSavepoint(); return conn.setSavepoint();
@@ -371,14 +364,20 @@ public class ConnectionPool {
return conn.setSavepoint(name); return conn.setSavepoint(name);
} }
@Override
public void setTransactionIsolation(int level) throws SQLException {
conn.setTransactionIsolation(level);
}
@Override @Override
public void setTypeMap(Map<String, Class<?>> map) throws SQLException { public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
conn.setTypeMap(map); conn.setTypeMap(map);
} }
@Override public void terminate() {
public boolean isWrapperFor(Class<?> iface) throws SQLException { try {
return conn.isWrapperFor(iface); conn.close();
} catch (final SQLException ex) {}
} }
@Override @Override

View File

@@ -1,28 +0,0 @@
package de.diddiz.util;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
public class Download
{
public static void download(URL u, File file) throws Exception {
if (!file.getParentFile().exists())
file.getParentFile().mkdir();
if (file.exists())
file.delete();
file.createNewFile();
final InputStream in = u.openStream();
final OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
final byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) >= 0) {
out.write(buffer, 0, len);
}
in.close();
out.close();
}
}

View File

@@ -0,0 +1,88 @@
package de.diddiz.util;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.text.ParseException;
import java.text.SimpleDateFormat;
public class Utils
{
public static void download(URL u, File file) throws Exception {
if (!file.getParentFile().exists())
file.getParentFile().mkdir();
if (file.exists())
file.delete();
file.createNewFile();
final InputStream in = u.openStream();
final OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
final byte[] buffer = new byte[1024];
int len;
while ((len = in.read(buffer)) >= 0)
out.write(buffer, 0, len);
in.close();
out.close();
}
public static boolean isInt(String str) {
try {
Integer.parseInt(str);
return true;
} catch (final NumberFormatException ex) {}
return false;
}
public static int parseTimeSpec(String[] spec) {
if (spec == null || spec.length < 1 || spec.length > 2)
return -1;
if (!spec[0].contains(":") || !spec[0].contains("."))
if (spec.length == 2) {
if (!isInt(spec[0]))
return -1;
int min = Integer.parseInt(spec[0]);
if (spec[1].startsWith("h"))
min *= 60;
else if (spec[1].startsWith("d"))
min *= 1440;
return min;
} else if (spec.length == 1) {
int days = 0, hours = 0, minutes = 0;
int lastIndex = 0, currIndex = 1;
while (currIndex <= spec[0].length()) {
while (currIndex <= spec[0].length() && isInt(spec[0].substring(lastIndex, currIndex)))
currIndex++;
if (currIndex - 1 != lastIndex) {
final String param = spec[0].substring(currIndex - 1, currIndex).toLowerCase();
if (param.equals("d"))
days = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1));
else if (param.equals("h"))
hours = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1));
else if (param.equals("m"))
minutes = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1));
lastIndex = currIndex;
currIndex++;
}
}
if (days == 0 && hours == 0 && minutes == 0)
return -1;
return minutes + hours * 60 + days * 1440;
} else
return -1;
final String timestamp;
if (spec.length == 1) {
if (spec[0].contains(":"))
timestamp = new SimpleDateFormat("dd.MM.yyyy").format(System.currentTimeMillis()) + " " + spec[0];
else
timestamp = spec[0] + " 00:00:00";
} else
timestamp = spec[0] + " " + spec[1];
try {
return (int)((System.currentTimeMillis() - new SimpleDateFormat("dd.MM.yyyy HH:mm:ss").parse(timestamp).getTime()) / 60000);
} catch (final ParseException ex) {
return -1;
}
}
}

View File

@@ -1,5 +1,5 @@
name: LogBlock name: LogBlock
version: 0.15b version: '1.00rc1'
author: DiddiZ, bootswithdefer author: DiddiZ, bootswithdefer
website: http://www.diddiz.de/minecraft/ website: http://www.diddiz.de/minecraft/
main: de.diddiz.LogBlock.LogBlock main: de.diddiz.LogBlock.LogBlock