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;
import java.io.Closeable;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
@ -8,184 +9,278 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
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.command.Command;
import org.bukkit.command.CommandExecutor;
import org.bukkit.command.CommandSender;
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.Order;
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
{
private final Logger log;
private final LogBlock logblock;
private final Config config;
private final BukkitScheduler scheduler;
private final LogBlockQuestioner questioner;
public CommandsHandler(LogBlock logblock) {
CommandsHandler(LogBlock logblock) {
this.logblock = logblock;
log = logblock.getServer().getLogger();
config = logblock.getConfig();
scheduler = logblock.getServer().getScheduler();
questioner = (LogBlockQuestioner)logblock.getServer().getPluginManager().getPlugin("LogBlockQuestioner");
}
@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"))
return false;
if (args.length == 0) {
sender.sendMessage(ChatColor.LIGHT_PURPLE + "LogBlock v" + logblock.getDescription().getVersion() + " by DiddiZ");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "Type /lb help for help");
} else if (args[0].equalsIgnoreCase("help")) {
sender.sendMessage(ChatColor.LIGHT_PURPLE + "LogBlock Commands:");
if (logblock.checkPermission(sender, "logblock.me"))
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb me");
if (logblock.checkPermission(sender, "logblock.area")) {
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb area <radius>");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb world");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb player [name] <radius>");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb block [type] <radius>");
}
if (logblock.checkPermission(sender, "logblock.rollback")) {
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb rollback [rollback mode]");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb redo [redo mode]");
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb writelogfile [player]");
}
if (logblock.checkPermission(sender, "logblock.hide"))
sender.sendMessage(ChatColor.LIGHT_PURPLE + "/lb hide");
} else if (args[0].equalsIgnoreCase("tool")) {
if (sender instanceof Player) {
if (logblock.checkPermission(sender, "logblock.tool"))
giveTool((Player)sender, config.toolID);
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 (args[0].equalsIgnoreCase("toolblock")) {
if (sender instanceof Player) {
if (logblock.checkPermission(sender, "logblock.toolblockID"))
giveTool((Player)sender, config.toolblockID);
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 (args[0].equalsIgnoreCase("hide")) {
if (sender instanceof Player) {
if (logblock.checkPermission(sender, "logblock.hide")) {
if (logblock.getConsumer().hide((Player)sender))
sender.sendMessage(ChatColor.GREEN + "You are now hided and won't appear in any log. Type '/lb hide' again to unhide");
} else {
final String command = args[0].toLowerCase();
if (command.equals("help")) {
sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Help:");
sender.sendMessage(ChatColor.GOLD + "For the commands list type '/lb commands'");
sender.sendMessage(ChatColor.GOLD + "For the parameters list type '/lb params'");
sender.sendMessage(ChatColor.GOLD + "For the list of permissions you got type '/lb permissions'");
} else if (command.equals("commands")) {
sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Commands:");
sender.sendMessage(ChatColor.GOLD + "/lb tool -- Gives you the lb tool");
sender.sendMessage(ChatColor.GOLD + "/lb tool [on|off] -- Enables/Disables tool");
sender.sendMessage(ChatColor.GOLD + "/lb tool [params] -- Sets the tool lookup query");
sender.sendMessage(ChatColor.GOLD + "/lb toolblock -- Analog to tool");
sender.sendMessage(ChatColor.GOLD + "/lb hide -- Hides you from log");
sender.sendMessage(ChatColor.GOLD + "/lb rollback [params] -- Rollback");
sender.sendMessage(ChatColor.GOLD + "/lb redo [params] -- Redo");
sender.sendMessage(ChatColor.GOLD + "/lb tp [params] -- Teleports you to the location of griefing");
sender.sendMessage(ChatColor.GOLD + "/lb writelogfile [params] -- Writes a log file");
sender.sendMessage(ChatColor.GOLD + "/lb lookup [params] -- Lookup");
sender.sendMessage(ChatColor.GOLD + "/lb me -- Displays your stats");
sender.sendMessage(ChatColor.GOLD + "Look at diddiz.insane-architects.net/logblock for the full commands reference");
} else if (command.equals("params")) {
sender.sendMessage(ChatColor.DARK_AQUA + "LogBlock Query Parameters:");
sender.sendMessage(ChatColor.GOLD + "Use doublequotes to escape a keyword: world \"world\"");
sender.sendMessage(ChatColor.GOLD + "player [name1] <name2> <name3> -- List of players");
sender.sendMessage(ChatColor.GOLD + "block [type1] <type2> <type3> -- List of block types");
sender.sendMessage(ChatColor.GOLD + "created, destroyed -- Show only created/destroyed blocks");
sender.sendMessage(ChatColor.GOLD + "chestaccess -- Show only chest accesses");
sender.sendMessage(ChatColor.GOLD + "area <radius> -- Area around you");
sender.sendMessage(ChatColor.GOLD + "selection, sel -- Inside current WorldEdit selection");
sender.sendMessage(ChatColor.GOLD + "world [worldname] -- Changes the world");
sender.sendMessage(ChatColor.GOLD + "time [number] [minutes|hours|days] -- Limits time");
sender.sendMessage(ChatColor.GOLD + "since <dd.MM.yyyy> <HH:mm:ss> -- Limits time to a fixed point");
sender.sendMessage(ChatColor.GOLD + "limit <row count> -- Limits the result to count of rows");
sender.sendMessage(ChatColor.GOLD + "sum [none|blocks|players] -- Sums the result");
sender.sendMessage(ChatColor.GOLD + "asc, desc -- Changes the order of the displayed log");
} else if (command.equals("permissions")) {
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
sender.sendMessage(ChatColor.GREEN + "You aren't hided anylonger.");
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this.");
} 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 (args[0].equalsIgnoreCase("savequeue")) {
if (logblock.checkPermission(sender, "logblock.rollback"))
try {
new Thread(new CommandSaveQueue(sender, null)).run();
} catch (Exception ex) {
sender.sendMessage(ex.getMessage());
}
else
sender.sendMessage(ChatColor.RED + "You aren't allowed to do this.");
} else if (args[0].equalsIgnoreCase("rollback") || args[0].equalsIgnoreCase("undo")) {
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.DESC);
params.setSummarizationMode(QueryParams.SummarizationMode.NONE);
new Thread(new CommandRollback(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("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);
sender.sendMessage(ChatColor.RED + "You have to be a player.");
} else if (command.equals("toolblock")) {
if (sender instanceof Player) {
final Player player = (Player)sender;
if (args.length == 1) {
if (logblock.hasPermission(player, "logblock.toolblock"))
BukkitUtils.giveTool(player, config.toolblockID);
else
player.sendMessage(ChatColor.RED + "You aren't allowed to do this.");
} else if (args[1].equalsIgnoreCase("enable") || args[1].equalsIgnoreCase("on")) {
logblock.getSession(player.getName()).toolBlockEnabled = true;
player.sendMessage(ChatColor.GREEN + "Tool block enabled.");
} else if (args[1].equalsIgnoreCase("disable") || args[1].equalsIgnoreCase("off")) {
logblock.getSession(player.getName()).toolBlockEnabled = false;
player.sendMessage(ChatColor.GREEN + "Tool block disabled.");
} else if (logblock.hasPermission(player, "logblock.lookup"))
try {
final QueryParams params = new QueryParams(logblock, sender, ArgsToList(args, 1));
logblock.getSession(player.getName()).toolBlockQuery = params;
sender.sendMessage(ChatColor.GREEN + "Set tool block query to: " + params.getTitle());
} 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 aren't allowed to do this.");
} else
sender.sendMessage(ChatColor.RED + "You have to be a player.");
} else if (args[0].equalsIgnoreCase("writelogfile")) {
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.setBlockChangeType(BlockChangeType.ALL);
params.setSummarizationMode(SummarizationMode.NONE);
new Thread(new CommandWriteLogFile(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("tp")) {
if (sender instanceof Player) {
if (logblock.checkPermission(sender,"logblock.tp")) {
sender.sendMessage(ChatColor.RED + "You have to be a player.");
} else if (command.equals("hide")) {
if (sender instanceof Player) {
if (logblock.hasPermission(sender, "logblock.hide")) {
if (logblock.getConsumer().hide((Player)sender))
sender.sendMessage(ChatColor.GREEN + "You are now hided and won't appear in any log. Type '/lb hide' again to unhide");
else
sender.sendMessage(ChatColor.GREEN + "You aren't hided anylonger.");
} 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 (args[0].equalsIgnoreCase("savequeue")) {
if (logblock.hasPermission(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);
new Thread(new CommandTeleport(sender, null)).run();
new CommandSaveQueue(sender, null);
} 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
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");
} else
sender.sendMessage(ChatColor.RED + "You have to be a player.");
} 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());
}
sender.sendMessage(ChatColor.RED + "Unknown command '" + args[0] + "'");
}
return true;
}
private abstract class LBCommand implements Runnable
public abstract class LBCommand implements Runnable, Closeable
{
protected final CommandSender sender;
protected final QueryParams params;
@ -196,20 +291,14 @@ public class CommandsHandler implements CommandExecutor
LBCommand(CommandSender sender, QueryParams params) throws Exception {
this.sender = sender;
this.params = params;
try {
conn = logblock.getConnection();
conn.setAutoCommit(false);
state = conn.createStatement();
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");
}
conn = logblock.getConnection();
state = conn.createStatement();
if (scheduler.scheduleAsyncDelayedTask(logblock, this) == -1)
throw new Exception("Failed to schedule the command");
}
protected void close() {
@Override
public final void close() {
try {
if (conn != null)
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 {
super(sender, params);
@ -232,15 +321,16 @@ public class CommandsHandler implements CommandExecutor
@Override
public void run() {
try {
final SummarizationMode sum = params.getSummarizationMode();
final HistoryFormatter histformatter = new HistoryFormatter(sum);
rs = state.executeQuery(params.getQuery());
sender.sendMessage(ChatColor.DARK_AQUA + params.getTitle());
if (rs.next()) {
rs.beforeFirst();
final SummarizationMode sum = params.sum;
final HistoryFormatter histformatter = new HistoryFormatter(sum);
if (sum == SummarizationMode.TYPES)
sender.sendMessage(ChatColor.GOLD + String.format("%-6s %-6s %s", "Creat", "Destr", "Block"));
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())
sender.sendMessage(ChatColor.GOLD + histformatter.format(rs));
} 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 {
super(sender, params);
@ -263,15 +353,16 @@ public class CommandsHandler implements CommandExecutor
@Override
public void run() {
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 String newline = System.getProperty("line.separator");
final HistoryFormatter histformatter = new HistoryFormatter(params.getSummarizationMode());
final HistoryFormatter histformatter = new HistoryFormatter(params.sum);
file.getParentFile().mkdirs();
sender.sendMessage(ChatColor.GREEN + "Creating " + file.getName());
while (rs.next()) {
while (rs.next())
writer.write(histformatter.format(rs) + newline);
}
writer.close();
sender.sendMessage(ChatColor.GREEN + "Done");
} 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 {
super(sender, params);
@ -296,14 +387,13 @@ public class CommandsHandler implements CommandExecutor
public void run() {
final Consumer consumer = logblock.getConsumer();
sender.sendMessage(ChatColor.DARK_AQUA + "Current queue size: " + consumer.getQueueSize());
while (consumer.getQueueSize() > 0) {
while (consumer.getQueueSize() > 0)
consumer.run();
}
sender.sendMessage(ChatColor.GREEN + "Queue saved successfully");
}
}
private class CommandTeleport extends LBCommand
public class CommandTeleport extends LBCommand
{
CommandTeleport(CommandSender sender, QueryParams params) throws Exception {
super(sender, params);
@ -312,21 +402,24 @@ public class CommandsHandler implements CommandExecutor
@Override
public void run() {
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()) {
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
sender.sendMessage(ChatColor.RED + "Query returned no result");
} catch (final SQLException ex) {
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 {
close();
}
}
}
private class CommandRollback extends LBCommand
public class CommandRollback extends LBCommand
{
CommandRollback(CommandSender sender, QueryParams params) throws Exception {
super(sender, params);
@ -335,38 +428,38 @@ public class CommandsHandler implements CommandExecutor
@Override
public void run() {
try {
final WorldEditor editor = new WorldEditor(logblock, this, params.getWorld());
while (rs.next()) {
editor.queueBlockChange(rs.getInt("type"), rs.getInt("replaced"), rs.getByte("data"), rs.getInt("x"), rs.getInt("y"), rs.getInt("z"));
}
rs = state.executeQuery(params.getQuery());
sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":");
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();
sender.sendMessage(ChatColor.GREEN + "" + changes + " Changes found.");
final long start = System.currentTimeMillis();
if (!editor.start()) {
sender.sendMessage(ChatColor.RED + "Failed to schedule rollback task");
sender.sendMessage(ChatColor.GREEN.toString() + changes + " blocks found.");
if (config.askRollbacks && questioner != null && sender instanceof Player && !questioner.askQuestion((Player)sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) {
sender.sendMessage(ChatColor.RED + "Rollback aborted");
return;
}
synchronized (this) {
try {
this.wait();
} catch (final InterruptedException e) {
sender.sendMessage(ChatColor.RED + "Rollback Interrupted");
log.severe("[LogBlock Rollback] Interrupted");
}
}
final long start = System.currentTimeMillis();
editor.start();
sender.sendMessage(ChatColor.GREEN + "Rollback finished successfully");
sender.sendMessage(ChatColor.GREEN + "Undid " + editor.getSuccesses() + " of " + changes + " changes (" + editor.getErrors() + " errors, " + editor.getBlacklistCollisions() + " blacklist collisions)");
sender.sendMessage(ChatColor.GREEN + "Took: " + (System.currentTimeMillis() - start) + "ms");
} catch (final SQLException ex) {
sender.sendMessage(ChatColor.RED + "SQL exception");
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 {
close();
}
}
}
private class CommandRedo extends LBCommand
public class CommandRedo extends LBCommand
{
CommandRedo(CommandSender sender, QueryParams params) throws Exception {
super(sender, params);
@ -375,39 +468,105 @@ public class CommandsHandler implements CommandExecutor
@Override
public void run() {
try {
final WorldEditor editor = new WorldEditor(logblock, this, params.getWorld());
while (rs.next()) {
editor.queueBlockChange(rs.getInt("replaced"), rs.getInt("type"), rs.getByte("data"), rs.getInt("x"), rs.getInt("y"), rs.getInt("z"));
}
rs = state.executeQuery(params.getQuery());
sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":");
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();
sender.sendMessage(ChatColor.GREEN + "" + changes + " Changes found.");
final long start = System.currentTimeMillis();
if (!editor.start()) {
sender.sendMessage(ChatColor.RED + "Failed to schedule redo task");
sender.sendMessage(ChatColor.GREEN.toString() + changes + " blocks found.");
if (config.askRedos && questioner != null && sender instanceof Player && !questioner.askQuestion((Player)sender, "Are you sure you want to continue?", "yes", "no").equals("yes")) {
sender.sendMessage(ChatColor.RED + "Redo aborted");
return;
}
synchronized (this) {
try {
this.wait();
} catch (final InterruptedException e) {
sender.sendMessage(ChatColor.RED + "Redo Interrupted");
log.severe("[LogBlock Redo] Interrupted");
}
}
final long start = System.currentTimeMillis();
editor.start();
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 + "Took: " + (System.currentTimeMillis() - start) + "ms");
} catch (final SQLException ex) {
sender.sendMessage(ChatColor.RED + "SQL exception");
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 {
close();
}
}
}
private String getMaterialName(int type) {
return Material.getMaterial(type).toString().toLowerCase().replace('_', ' ');
public class CommandClearLog extends LBCommand
{
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
@ -422,50 +581,56 @@ public class CommandsHandler implements CommandExecutor
String format(ResultSet rs) {
try {
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 replaced = rs.getInt("replaced");
if ((type == 63 || type == 68) && rs.getString("signtext") != null)
msg.append("created " + rs.getString("signtext"));
else if (type == replaced) {
if (type == 23 || type == 54 || type == 61)
msg.append("looked inside " + getMaterialName(type));
final String signtext;
if ((type == 63 || type == 68 || replaced == 63 || replaced == 68) && (signtext = rs.getString("signtext")) != null) {
final String action;
if (type == 0)
action = "destroyed ";
else
action = "created ";
if (!signtext.contains("\0"))
msg.append(action + signtext);
else
msg.append(action + "sign [" + signtext.replace("\0", "] [") + "]");
} else if (type == replaced) {
if (type == 0)
msg.append("did a unspecified action");
else if (type == 23 || type == 54 || type == 61) {
final int itemType = rs.getInt("itemtype");
final int itemAmount = rs.getInt("itemamount");
if (itemType == 0 || itemAmount == 0)
msg.append("looked inside " + BukkitUtils.getMaterialName(type));
else if (itemAmount < 0)
msg.append("took " + itemAmount * -1 + "x " + BukkitUtils.getMaterialName(itemType));
else
msg.append("put in " + itemAmount + "x " + BukkitUtils.getMaterialName(itemType));
}
} else if (type == 0)
msg.append("destroyed " + getMaterialName(replaced));
msg.append("destroyed " + BukkitUtils.getMaterialName(replaced));
else if (replaced == 0)
msg.append("created " + getMaterialName(type));
msg.append("created " + BukkitUtils.getMaterialName(type));
else
msg.append("replaced " + getMaterialName(replaced) + " with " + getMaterialName(type));
msg.append("replaced " + BukkitUtils.getMaterialName(replaced) + " with " + BukkitUtils.getMaterialName(type));
return msg.toString();
} else if (sum == SummarizationMode.TYPES)
return fillWithSpaces(rs.getInt("created")) + fillWithSpaces(rs.getInt("destroyed")) + Material.getMaterial(rs.getInt("type")).toString().toLowerCase().replace('_', ' ');
return fillWithSpaces(rs.getInt("created")) + fillWithSpaces(rs.getInt("destroyed")) + BukkitUtils.getMaterialName(rs.getInt("type"));
else
return fillWithSpaces(rs.getInt("created")) + fillWithSpaces(rs.getInt("destroyed")) + rs.getString("playername");
} catch (final Exception ex) {
log.log(Level.SEVERE, "[LogBlock HistoryFormatter] Error", ex);
return null;
}
}
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;
for (int i = 0; i < neededSpaces; i++)
filled.append(' ');;
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");
filled.append(' ');
return filled.toString();
}
}
}

View File

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

View File

@ -10,19 +10,18 @@ import java.util.TimerTask;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Location;
import org.bukkit.World;
import org.bukkit.block.BlockState;
import org.bukkit.block.Chest;
import org.bukkit.block.Dispenser;
import org.bukkit.block.Furnace;
import org.bukkit.block.ContainerBlock;
import org.bukkit.block.Sign;
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;
import de.diddiz.util.BukkitUtils;
public class Consumer extends TimerTask implements Runnable
public class Consumer extends TimerTask
{
private final LogBlock logblock;
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, Long> lastAttackTime = new HashMap<Integer, Long>();
Consumer (LogBlock logblock) {
Consumer(LogBlock logblock) {
this.logblock = logblock;
log = logblock.getServer().getLogger();
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).
* @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) {
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).
* @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) {
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 after Blockstate of the block after actually being placed.
* @param before
* 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) {
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) {
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) {
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) {
if (dataBefore == 0) {
if (dataBefore == 0)
queueBlock(playerName, loc, typeBefore, typeAfter, dataAfter);
} else {
else {
queueBlockBreak(playerName, loc, typeBefore, dataBefore);
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) {
queueBlock(playerName, loc, typeBefore, typeAfter, data, null, null);
public void queueChestAccess(String playerName, BlockState container, short itemType, short itemAmount, byte itemData) {
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 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.
* @param type
* Type id of the container. Must be 63 or 68.
* @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) {
if (!(container instanceof Chest) && !(container instanceof Furnace) && !(container instanceof Dispenser))
public void queueChestAccess(String playerName, Location loc, int type, short itemType, short itemAmount, byte itemData) {
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;
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 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, 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
* @param killer
* Can' be null
* @param victim
* Can' be null
*/
public void queueKill(Entity killer, Entity victim) {
if (killer == null || victim == null)
if (killer == null || victim == null)
return;
if (lastAttackedEntity.containsKey(killer.getEntityId()) && lastAttackedEntity.get(killer.getEntityId()) == victim.getEntityId() && System.currentTimeMillis() - lastAttackTime.get(killer.getEntityId()) < 5000)
return;
@ -169,14 +193,18 @@ public class Consumer extends TimerTask implements Runnable
weapon = ((Player)killer).getItemInHand().getTypeId();
lastAttackedEntity.put(killer.getEntityId(), victim.getEntityId());
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 killerName 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.
* @param world
* World the victim was inside.
* @param killerName
* 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) {
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));
}
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) {
final int hash = player.getName().hashCode();
if (hiddenplayers.contains(hash)) {
hiddenplayers.remove(hash);
return false;
} else {
hiddenplayers.add(hash);
return true;
}
public void queueSignBreak(String playerName, Sign sign) {
queueSignBreak(playerName, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getTypeId(), sign.getRawData(), sign.getLines());
}
/**
* @param type
* Type of the sign. Must be 63 or 68.
* @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
@ -205,7 +250,9 @@ public class Consumer extends TimerTask implements Runnable
if (conn == null)
return;
Statement state = null;
BlockRow b; KillRow k; String table;
BlockRow b;
KillRow k;
String table;
if (getQueueSize() > 1000)
log.info("[LogBlock Consumer] Queue overloaded. Size: " + getQueueSize());
try {
@ -214,7 +261,7 @@ public class Consumer extends TimerTask implements Runnable
final long start = System.currentTimeMillis();
int count = 0;
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();
if (b == null)
continue;
@ -225,13 +272,13 @@ public class Consumer extends TimerTask implements Runnable
if (keys.next())
state.execute("INSERT INTO `" + table + "-sign` (id, signtext) values (" + keys.getInt(1) + ", '" + b.signtext + "')");
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) {
final ResultSet keys = state.getGeneratedKeys();
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
log.severe("[LogBlock Consumer] Failed to get generated keys");
log.warning("[LogBlock Consumer] Failed to get generated keys. Unable to log chest access.");
}
count++;
if (count % 100 == 0)
@ -240,7 +287,7 @@ public class Consumer extends TimerTask implements Runnable
conn.commit();
}
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();
if (k == null)
continue;
@ -255,38 +302,16 @@ public class Consumer extends TimerTask implements Runnable
log.log(Level.SEVERE, "[LogBlock Consumer] SQL exception", ex);
} finally {
try {
if (conn != null)
conn.close();
if (state != null)
state.close();
conn.close();
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock Consumer] SQL exception on close", ex);
}
}
}
private String getEntityName(Entity entity) {
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
private static class BlockRow
{
public final int worldHash;
public final String name;
@ -296,7 +321,7 @@ public class Consumer extends TimerTask implements Runnable
public final String signtext;
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.name = name;
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 String killer;
@ -323,24 +360,5 @@ public class Consumer extends TimerTask implements Runnable
victim = defender;
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;
import org.bukkit.Material;
import org.bukkit.block.BlockFace;
import org.bukkit.block.BlockState;
import org.bukkit.block.Sign;
import org.bukkit.event.block.BlockBreakEvent;
import org.bukkit.event.block.BlockBurnEvent;
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.SignChangeEvent;
public class LBBlockListener extends BlockListener
class LBBlockListener extends BlockListener
{
private final Config config;
private final Consumer consumer;
private final boolean logSignTexts;
private final boolean logChestAccess;
LBBlockListener(LogBlock logblock) {
config = logblock.getConfig();
consumer = logblock.getConsumer();
logSignTexts = logblock.getConfig().logSignTexts;
logChestAccess = logblock.getConfig().logChestAccess;
}
@Override
@ -26,22 +28,23 @@ public class LBBlockListener extends BlockListener
if (!event.isCancelled()) {
final int typeFrom = event.getBlock().getTypeId();
final int typeTo = event.getToBlock().getTypeId();
if (typeFrom == 10 || typeFrom == 11) {
if (typeFrom == 10 || typeFrom == 11)
if (typeTo == 0 || typeTo == 78)
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)
consumer.queueBlockReplace("LavaFlow", event.getToBlock().getState(), 10, (byte)0);
else
consumer.queueBlockReplace("LavaFlow", event.getToBlock().getState(), 4, (byte)0);
}
}
}
}
@Override
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 after = event.getBlockPlaced().getState();
if (before.getTypeId() == 0)
@ -53,14 +56,21 @@ public class LBBlockListener extends BlockListener
@Override
public void onBlockBreak(BlockBreakEvent event) {
if (!event.isCancelled())
consumer.queueBlockBreak(event.getPlayer().getName(), event.getBlock().getState());
if (!event.isCancelled()) {
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
public void onSignChange(SignChangeEvent event) {
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

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;
import org.bukkit.block.Block;
import org.bukkit.block.Sign;
import org.bukkit.entity.Creeper;
import org.bukkit.entity.Entity;
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.EntityListener;
public class LBEntityListener extends EntityListener
class LBEntityListener extends EntityListener
{
private final Config config;
private final Consumer consumer;
private final boolean logSignTexts;
private final boolean logChestAccess;
private final boolean logCreeperExplosionsAsPlayer;
private final Config.LogKillsLevel logKillsLevel;
LBEntityListener(LogBlock logblock) {
config= logblock.getConfig();
consumer = logblock.getConsumer();
logSignTexts = logblock.getConfig().logSignTexts;
logChestAccess = logblock.getConfig().logChestAccess;
logCreeperExplosionsAsPlayer = logblock.getConfig().logCreeperExplosionsAsPlayerWhoTriggeredThese;
logKillsLevel = logblock.getConfig().logKillsLevel;
}
@Override
@ -29,14 +36,28 @@ public class LBEntityListener extends EntityListener
String name;
if (event.getEntity() instanceof TNTPrimed)
name = "TNT";
else if (event.getEntity() instanceof Creeper)
name = "Creeper";
else if (event.getEntity() instanceof Fireball)
else if (event.getEntity() instanceof Creeper) {
if (logCreeperExplosionsAsPlayer) {
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";
else
name = "Environment";
for (final Block block : event.blockList())
consumer.queueBlockBreak(name, block.getState());
for (final Block block : event.blockList()) {
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;
final LivingEntity victim = (LivingEntity)event.getEntity();
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;
if (config.logKillsLevel == Config.LogKillsLevel.PLAYERS && !(victim instanceof Player && killer instanceof Player))
if (logKillsLevel == Config.LogKillsLevel.PLAYERS && !(victim instanceof Player && killer instanceof Player))
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;
consumer.queueKill(killer, victim);
}

View File

@ -5,16 +5,13 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.bukkit.Material;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerBucketEmptyEvent;
import org.bukkit.event.player.PlayerBucketFillEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.event.player.PlayerListener;
public class LBPlayerListener extends PlayerListener
class LBPlayerListener extends PlayerListener
{
private final Logger log;
private final LogBlock logblock;
@ -26,12 +23,6 @@ public class LBPlayerListener extends PlayerListener
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
public void onPlayerBucketFill(PlayerBucketFillEvent event) {
if (!event.isCancelled())
@ -63,8 +54,7 @@ public class LBPlayerListener extends PlayerListener
try {
if (state != null)
state.close();
if (conn != null)
conn.close();
conn.close();
} catch (final SQLException 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.logging.Level;
import java.util.logging.Logger;
import org.bukkit.command.CommandSender;
import org.bukkit.command.ConsoleCommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.Event.Priority;
import org.bukkit.event.Event.Type;
import org.bukkit.plugin.PluginManager;
import org.bukkit.plugin.java.JavaPlugin;
import com.nijiko.permissions.PermissionHandler;
import com.nijikokun.bukkit.Permissions.Permissions;
import de.diddiz.LogBlock.QueryParams.BlockChangeType;
import de.diddiz.util.ConnectionPool;
import de.diddiz.util.Download;
import de.diddiz.util.Utils;
// TODO Add painting logging
// TODO Add Button, lever etc logging
public class LogBlock extends JavaPlugin
{
@ -32,10 +34,11 @@ public class LogBlock extends JavaPlugin
private Config config;
private ConnectionPool pool;
private Consumer consumer = null;
private CommandsHandler commandsHandler;
private Timer timer = null;
private PermissionHandler permissions = null;
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() {
return config;
@ -45,10 +48,14 @@ public class LogBlock extends JavaPlugin
return consumer;
}
public CommandsHandler getCommandsHandler() {
return commandsHandler;
}
@Override
public void onLoad() {
log = getServer().getLogger();
try {
try {
config = new Config(this);
} catch (final Exception ex) {
log.log(Level.SEVERE, "[LogBlock] Exception while reading config:", ex);
@ -59,7 +66,7 @@ public class LogBlock extends JavaPlugin
try {
if (!file.exists() || file.length() == 0) {
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)
throw new FileNotFoundException(file.getAbsolutePath() + file.getName());
@ -71,8 +78,7 @@ public class LogBlock extends JavaPlugin
try {
log.info("[LogBlock] Connecting to " + config.user + "@" + config.url + "...");
pool = new ConnectionPool(config.url, config.user, config.password);
final Connection conn = getConnection();
conn.close();
getConnection().close();
} catch (final Exception ex) {
log.log(Level.SEVERE, "[LogBlock] Exception while checking database connection", ex);
errorAtLoading = true;
@ -92,19 +98,28 @@ public class LogBlock extends JavaPlugin
getServer().getPluginManager().disablePlugin(this);
return;
}
getCommand("lb").setExecutor(new CommandsHandler(this));
commandsHandler = new CommandsHandler(this);
getCommand("lb").setExecutor(commandsHandler);
if (getServer().getPluginManager().getPlugin("Permissions") != null) {
permissions = ((Permissions)getServer().getPluginManager().getPlugin("Permissions")).getHandler();
log.info("[LogBlock] Permissions enabled");
log.info("[LogBlock] Permissions found.");
} else
log.info("[LogBlock] Permissions plugin not found. Using default permissions.");
if (config.keepLogDays >= 0)
new Thread(new ClearLog(this)).start();
if (config.keepLogDays >= 0) {
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 LBPlayerListener lbPlayerListener = new LBPlayerListener(this);
final LBEntityListener lbEntityListener = new LBEntityListener(this);
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);
if (config.logBlockCreations) {
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);
if (config.logLeavesDecay)
pm.registerEvent(Type.LEAVES_DECAY, lbBlockListener, Priority.Monitor, this);
if (config.logChestAccess)
pm.registerEvent(Type.PLAYER_INTERACT, lbPlayerListener, Priority.Monitor, this);
if (config.logChestAccess) {
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)
pm.registerEvent(Type.BLOCK_FROMTO, lbBlockListener, Priority.Monitor, this);
if (config.logKills)
@ -157,7 +175,7 @@ public class LogBlock extends JavaPlugin
}
}
if (pool != null)
pool.closeConnections();
pool.close();
log.info("LogBlock disabled.");
}
@ -169,17 +187,17 @@ public class LogBlock extends JavaPlugin
try {
final DatabaseMetaData dbm = conn.getMetaData();
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.");
state.execute("CREATE TABLE `lb-players` (playerid SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, playername varchar(32) NOT NULL DEFAULT '-', PRIMARY KEY (playerid), UNIQUE (playername))");
if (!dbm.getTables(null, null, "lb-players", null).next())
return false;
}
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()) {
if (!dbm.getTables(null, null, table, null).next()) {
if (!dbm.getTables(null, null, table, null).next()) {
log.log(Level.INFO, "[LogBlock] Crating table " + table + ".");
state.execute("CREATE TABLE `" + table + "` (id INT NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL 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())
return false;
}
@ -191,7 +209,7 @@ public class LogBlock extends JavaPlugin
}
if (!dbm.getTables(null, null, table + "-chest", null).next()) {
log.log(Level.INFO, "[LogBlock] Crating table " + table + "-chest.");
state.execute("CREATE TABLE `" + table + "-chest` (id INT NOT NULL, 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())
return false;
}
@ -209,8 +227,7 @@ public class LogBlock extends JavaPlugin
try {
if (state != null)
state.close();
if (conn != null)
conn.close();
conn.close();
} catch (final SQLException ex) {
log.log(Level.SEVERE, "[LogBlock] SQL exception on close", ex);
}
@ -218,42 +235,15 @@ public class LogBlock extends JavaPlugin
return false;
}
boolean checkPermission(CommandSender sender, String permission) {
boolean hasPermission(CommandSender sender, String permission) {
if (permissions != null && sender instanceof Player)
return permissions.permission((Player)sender, permission);
else {
if (permission.equals("logblock.area"))
return sender.isOp();
else if (permission.equals("logblock.hide"))
return sender.isOp();
else if (permission.equals("logblock.rollback"))
return sender.isOp();
return true;
}
if (permission.equals("logblock.lookup") || permission.equals("logblock.hide") || permission.equals("logblock.rollback"))
return sender.isOp();
return true;
}
static int parseTimeSpec(String timespec) {
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() {
Connection getConnection() {
try {
return pool.getConnection();
} catch (final SQLException ex) {
@ -261,11 +251,11 @@ public class LogBlock extends JavaPlugin
return null;
}
}
public Session getSession(String playerName) {
Session session = sessions.get(playerName.hashCode());
if (session == null) {
session = new Session();
session = new Session(this);
sessions.put(playerName.hashCode(), 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;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.bukkit.selections.CuboidSelection;
import com.sk89q.worldedit.bukkit.selections.Selection;
import de.diddiz.util.BukkitUtils;
import de.diddiz.util.Utils;
public class QueryParams
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 List<String> players = new ArrayList<String>();
private final List<Integer> types = new ArrayList<Integer>();
private Location loc = null;
private int radius = -1;
private Selection sel = null;
private int minutes = -1;
private SummarizationMode sum = SummarizationMode.NONE;;
private BlockChangeType bct = BlockChangeType.BOTH;
private int limit = 15;
private World world = null;
private Order order = Order.DESC;
List<String> players = new ArrayList<String>();
List<Integer> types = new ArrayList<Integer>();
Location loc = null;
int radius = -1;
Selection sel = null;
int minutes = 0;
SummarizationMode sum = SummarizationMode.NONE;
BlockChangeType bct = BlockChangeType.BOTH;
int limit = 15;
World world = null;
Order order = Order.DESC;
boolean selectFullBlockData = false;
boolean prepareToolQuery = false;
public QueryParams(LogBlock logblock) {
this.logblock = logblock;
}
public void merge (QueryParams params) {
loc = params.getLoc();
radius = params.getRadius();
sel = params.getSel();
minutes = params.getMinutes();
sum = params.getSummarizationMode();
bct = params.getBlockChangeType();
limit = params.limit;
world = params.getWorld();
order = params.getOrder();
public QueryParams(LogBlock logblock, CommandSender sender, List<String> args) throws IllegalArgumentException {
this.logblock = logblock;
parseArgs(sender, args);
}
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;
if (sender instanceof Player)
player = (Player)sender;
String name = "Console";
if (player != null)
name = player.getName();
final Session session = logblock.getSession(name);
if (!args.isEmpty() && args.get(0).equalsIgnoreCase("last") && session.getLastQuery() != null)
merge(session.getLastQuery());
final String name = BukkitUtils.getSenderName(sender);
final Session session;
if (!prepareToolQuery)
session = logblock.getSession(name);
else
session = null;
if (player != null && world == null)
world = player.getWorld();
for (int i = 0; i < args.size(); i++) {
final String param = args.get(i).toLowerCase();
final String[] values = getValues(args, i +1);
if (values != null)
i += values.length;
if (param.equals("player")) {
final String[] values = getValues(args, i + 1);
if (param.equals("last")) {
if (session.lastQuery == null)
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)
throw new Exception("No or wrong count of arguments for '" + param + "'");
for (final String playerName : values) {
throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'");
for (final String playerName : values)
if (playerName.length() > 0)
players.add(playerName);
}
} else if (param.equals("block")) {
} else if (param.equals("block") || param.equals("type")) {
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) {
final Material mat = Material.matchMaterial(blockName);
if (mat == null)
throw new Exception("No material matching: '" + blockName + "'");
throw new IllegalArgumentException("No material matching: '" + blockName + "'");
types.add(mat.getId());
}
} else if (param.equals("area")) {
if (player == null)
throw new Exception("You have to ba a player to use area");
if (player == null && !prepareToolQuery)
throw new IllegalArgumentException("You have to ba a player to use area");
if (values == null) {
radius = logblock.getConfig().defaultDist;
loc = player.getLocation();
if (!prepareToolQuery)
loc = player.getLocation();
} else {
if (!isInt(values[0]))
throw new Exception("Not a number: '" + values[0] + "'");
if (!Utils.isInt(values[0]))
throw new IllegalArgumentException("Not a number: '" + 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)
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");
if (we == null)
throw new Exception("WorldEdit plugin not found");
final Selection sel = ((WorldEditPlugin)we).getSelection(player);
throw new IllegalArgumentException("WorldEdit plugin not found");
sel = ((WorldEditPlugin)we).getSelection(player);
if (sel == null)
throw new Exception("No selection defined");
throw new IllegalArgumentException("No selection defined");
if (!(sel instanceof CuboidSelection))
throw new Exception("You have to define a cuboid selection");
this.sel = sel;
} else if (param.equals("time")) {
throw new IllegalArgumentException("You have to define a cuboid selection");
world = sel.getWorld();
} else if (param.equals("time") || param.equals("since")) {
if (values == null)
minutes = logblock.getConfig().defaultTime;
else {
if (values.length != 2)
throw new Exception("Wrong count of arguments for '" + param + "'");
if (!isInt(values[0]))
throw new Exception("Not a number: '" + values[0] + "'");
minutes = Integer.parseInt(values[0]);
if (values[1].startsWith("h"))
minutes *= 60;
else if (values[1].startsWith("d"))
minutes *= 60*24;
}
} else if (param.equals("since")) {
throw new Exception("Since parameter not implemented yet");
else
minutes = Utils.parseTimeSpec(values);
if (minutes == -1)
throw new IllegalArgumentException("Faile to parse time spec for '" + param + "'");
} else if (param.equals("before")) {
if (values == null)
minutes = logblock.getConfig().defaultTime * -1;
else
minutes = Utils.parseTimeSpec(values) * -1;
if (minutes == 1)
throw new IllegalArgumentException("Faile to parse time spec for '" + param + "'");
} else if (param.equals("sum")) {
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"))
sum = SummarizationMode.PLAYERS;
else if (values[0].startsWith("b"))
@ -128,37 +145,57 @@ public class QueryParams
else if (values[0].startsWith("n"))
sum = SummarizationMode.NONE;
else
throw new Exception("Wrong summarization mode");
} else if (param.equals("created")) {
throw new IllegalArgumentException("Wrong summarization mode");
} else if (param.equals("created"))
bct = BlockChangeType.CREATED;
} else if (param.equals("destroyed")) {
else if (param.equals("destroyed"))
bct = BlockChangeType.DESTROYED;
} else if (param.equals("chestaccess")) {
else if (param.equals("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)
throw new Exception("Wrong count of arguments for '" + param + "'");
if (!isInt(values[0]))
throw new Exception("Not a number: '" + values[0] + "'");
throw new IllegalArgumentException("Wrong count of arguments for '" + param + "'");
if (!Utils.isInt(values[0]))
throw new IllegalArgumentException("Not a number: '" + values[0] + "'");
limit = Integer.parseInt(values[0]);
} else if (param.equals("world")) {
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)
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]);
} else if (param.equals("ASC")) {
} else if (param.equals("asc"))
order = Order.ASC;
} else if (param.equals("DESC")) {
else if (param.equals("desc"))
order = Order.DESC;
} else
throw new Exception("Not a valid argument: '" + param + "'");
else
throw new IllegalArgumentException("Not a valid argument: '" + param + "'");
if (values != null)
i += values.length;
}
if (world == null)
throw new Exception("No world specified");
if (!logblock.getConfig().tables.containsKey(world.getName().hashCode()))
throw new Exception("This world ('" + world.getName() + "') isn't logged");
session.setLast(this);
if (types.size() > 0)
for (final Set<Integer> equivalent : BukkitUtils.getBlockEquivalents()) {
boolean found = false;
for (final Integer type : types)
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) {
@ -166,217 +203,185 @@ public class QueryParams
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() {
return logblock.getConfig().tables.get(world.getName().hashCode());
}
public String getTitle() {
final StringBuffer buffer = new StringBuffer();
final StringBuilder title = new StringBuilder();
if (!types.isEmpty()) {
for (int i = 0; i < types.size(); i++) {
buffer.append(getMaterialName(types.get(i)) + ", ");
}
buffer.deleteCharAt(buffer.length() - 2);
for (int i = 0; i < types.size(); i++)
title.append(BukkitUtils.getMaterialName(types.get(i)) + ", ");
title.deleteCharAt(title.length() - 2);
} else
buffer.append("Block ");
title.append("Block ");
if (bct == BlockChangeType.CREATED)
buffer.append("creations ");
else if (bct == BlockChangeType.DESTROYED)
buffer.append("destructions ");
title.append("creations ");
else if (bct == BlockChangeType.DESTROYED)
title.append("destructions ");
else
buffer.append("changes ");
title.append("changes ");
if (!players.isEmpty()) {
buffer.append("from player ");
for (int i = 0; i < players.size(); i++) {
buffer.append(players.get(i) + ", ");
}
buffer.deleteCharAt(buffer.length() - 2);
title.append("from player ");
for (int i = 0; i < players.size(); i++)
title.append(players.get(i) + ", ");
title.deleteCharAt(title.length() - 2);
}
if (loc != null && radius >= 0)
buffer.append("within " + radius + " blocks of you:");
if (minutes > 0)
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)
buffer.append("in selection:");
else
buffer.append("in entire world:");
buffer.setCharAt(0,String.valueOf(buffer.charAt(0)).toUpperCase().toCharArray()[0]);
return buffer.toString();
title.append("inside selection ");
title.append("in " + getfriendlyWorldname());
title.setCharAt(0, String.valueOf(title.charAt(0)).toUpperCase().toCharArray()[0]);
return title.toString();
}
public String getQuery() {
final StringBuffer where = new StringBuffer();
switch (bct) {
case ALL:
if (!types.isEmpty()) {
where.append('(');
for (final int type: types) {
where.append("type = " + type + " OR replaced = " + type + " OR ");
public String getOrderBy() {
return "ORDER BY date " + order + ", id " + order + " ";
}
public String getLimit() {
if (limit == -1)
return "";
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);
where.append(") AND ");
}
break;
case BOTH:
where.append("type <> replaced AND ");
if (!types.isEmpty()) {
where.append('(');
for (final int type: types) {
where.append("type = " + type + " OR replaced = " + type + " OR ");
break;
case BOTH:
where.append("type <> replaced AND ");
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());
where.append(") AND ");
}
where.delete(where.length() - 4, where.length());
where.append(") AND ");
}
break;
case CREATED:
where.append("type <> replaced AND ");
if (!types.isEmpty()) {
where.append('(');
for (final int type: types) {
where.append("type = " + type + " OR ");
}
where.delete(where.length() - 4, where.length());
where.append(") AND ");
} else
where.append("type > 0 AND ");
break;
case DESTROYED:
where.append("type <> replaced AND ");
if (!types.isEmpty()) {
where.append('(');
for (final int type: types) {
where.append("replaced = " + type + " OR ");
}
where.delete(where.length() - 4, where.length());
where.append(") AND ");
} else
where.append("replaced > 0 AND ");
break;
case CHESTACCESS:
where.append("type = replaced AND (type = 23 OR type = 54 OR type = 61) ");
break;
break;
case CREATED:
where.append("type <> replaced AND ");
if (!types.isEmpty()) {
where.append('(');
for (final int type : types)
where.append("type = " + type + " OR ");
where.delete(where.length() - 4, where.length());
where.append(") AND ");
} else
where.append("type > 0 AND ");
break;
case DESTROYED:
where.append("type <> replaced AND ");
if (!types.isEmpty()) {
where.append('(');
for (final int type : types)
where.append("replaced = " + type + " OR ");
where.delete(where.length() - 4, where.length());
where.append(") AND ");
} else
where.append("replaced > 0 AND ");
break;
case CHESTACCESS:
where.append("type = replaced AND (type = 23 OR type = 54 OR type = 61) AND ");
break;
}
if (!players.isEmpty() && sum != SummarizationMode.PLAYERS) {
where.append('(');
for (final String playerName: players) {
for (final String playerName : players)
where.append("playername = '" + playerName + "' OR ");
}
where.delete(where.length() - 4, where.length());
where.append(") AND ");
}
if (loc != null && radius >= 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)
if (loc != null) {
if (radius == 0)
where.append("x = '" + loc.getBlockX() + "' AND y = '" + loc.getBlockY() + "' AND z = '" + loc.getBlockZ() + "' AND ");
else if (radius > 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.delete(where.length() - 4, where.length());
if (sum == SummarizationMode.NONE) {
final StringBuffer sql = new StringBuffer("SELECT date, replaced, type, playername FROM `" + getTable() + "` INNER JOIN `lb-players` USING (playerid) ");
if (bct == BlockChangeType.ALL)
sql.append("LEFT JOIN `" + getTable() + "-sign` USING (id) ");
if (bct == BlockChangeType.ALL || bct == BlockChangeType.CHESTACCESS)
sql.append("LEFT JOIN `" + getTable() + "-chest` USING (id) ");
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";
}
if (minutes < 0)
where.append("date < date_sub(now(), INTERVAL " + minutes * -1 + " MINUTE) AND ");
if (where.length() > 6)
where.delete(where.length() - 4, where.length());
else
where.delete(0, where.length());
return where.toString();
}
private String getMaterialName(int type) {
return Material.getMaterial(type).toString().toLowerCase().replace('_', ' ');
public String getQuery() {
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) {
int i;
for (i = offset; i < args.size(); i++) {
for (i = offset; i < args.size(); i++)
if (isKeyWord(args.get(i)))
break;
}
if (i == offset)
return null;
else {
final String[] values = new String[i - offset];
System.arraycopy(args.toArray(), offset, values, 0, i - offset);
return values;
}
final String[] values = new String[i - offset];
for (int j = offset; j < i; j++)
values[j - offset] = args.get(j).replace("\"", "");
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 {
Integer.parseInt(str);
return true;
} catch (final Exception ex) {
return false;
}
return (QueryParams)super.clone();
} catch (final CloneNotSupportedException ex) {}
return null;
}
public static boolean isKeyWord(String param) {
final String key = new String(param).toLowerCase();
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"))
static boolean isKeyWord(String param) {
if (keywords.contains(param.toLowerCase().hashCode()))
return true;
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;
public class Session {
private QueryParams last = null;
public class Session
{
public QueryParams lastQuery = null;
public QueryParams toolQuery;
public QueryParams toolBlockQuery;
public boolean toolEnabled = true;
public boolean toolBlockEnabled = true;
public QueryParams getLastQuery() {
return last;
}
public void setLast(QueryParams params) {
last = params;
Session(LogBlock logblock) {
toolQuery = logblock.getConfig().toolQuery.clone();
toolBlockQuery = logblock.getConfig().toolBlockQuery.clone();
}
}

View File

@ -2,16 +2,29 @@ package de.diddiz.LogBlock;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.logging.Logger;
import org.bukkit.World;
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 static class WorldEditorException extends Exception
{
private static final long serialVersionUID = 7509084196124728986L;
public WorldEditorException(String msg) {
super(msg);
}
}
private final Logger log;
private final LogBlock logblock;
private final Config config;
private final Object caller;
private final LinkedBlockingQueue<Edit> edits = new LinkedBlockingQueue<Edit>();
private final World world;
private int taskID;
@ -19,101 +32,91 @@ public class WorldEditor implements Runnable
private int errors = 0;
private int blacklistCollisions = 0;
WorldEditor(LogBlock logblock, Object caller, World world) {
WorldEditor(LogBlock logblock, World world) {
log = logblock.getServer().getLogger();
this.logblock = logblock;
config = logblock.getConfig();
this.caller = caller;
this.world = world;
}
public int getSize() {
int getSize() {
return edits.size();
}
public int getSuccesses() {
int getSuccesses() {
return successes;
}
public int getErrors() {
int getErrors() {
return errors;
}
public int getBlacklistCollisions() {
int getBlacklistCollisions() {
return blacklistCollisions;
}
public void queueBlockChange(int type, int replaced, byte data, int x, int y, int z) {
edits.add(new Edit(type, replaced, data, x, y, 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, signtext, itemType, itemAmount, itemData));
}
public boolean start() {
synchronized void start() throws WorldEditorException {
taskID = logblock.getServer().getScheduler().scheduleSyncRepeatingTask(logblock, this, 0, 1);
if (taskID == -1)
return false;
return true;
throw new WorldEditorException("Failed to schedule task");
try {
this.wait();
} catch (final InterruptedException ex) {
throw new WorldEditorException("Interrupted");
}
}
@Override
public void run() {
public synchronized void run() {
int counter = 0;
while (!edits.isEmpty() && counter < 1000) {
switch (edits.poll().perform()) {
case SUCCESS:
successes++;
break;
case ERROR:
errors++;
break;
case BLACKLISTED:
blacklistCollisions++;
break;
case SUCCESS:
successes++;
break;
case ERROR:
errors++;
break;
case BLACKLISTED:
blacklistCollisions++;
break;
}
counter++;
}
if (edits.isEmpty()) {
logblock.getServer().getScheduler().cancelTask(taskID);
synchronized (caller) {
caller.notify();
}
notify();
}
}
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;
}
private enum PerformResult {
private static enum PerformResult {
ERROR, SUCCESS, BLACKLISTED, NO_ACTION
}
private class Edit
{
final int type, replaced;
final int x, y, z;
final byte data;
private final int type, replaced;
private final int x, y, z;
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.replaced = replaced;
this.data = data;
this.x = x;
this.y = y;
this.z = z;
this.signtext = signtext;
this.itemType = itemType;
this.itemAmount = itemAmount;
this.itemData = itemData;
}
private PerformResult perform() {
@ -121,19 +124,50 @@ public class WorldEditor implements Runnable
return PerformResult.BLACKLISTED;
try {
final Block block = world.getBlockAt(x, y, z);
final BlockState state = block.getState();
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
if (type == replaced)
if (type == 0) {
if (block.setTypeId(0))
return PerformResult.SUCCESS;
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;
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) {
log.severe("[LogBlock Rollback] " + ex.toString());
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;
import java.io.Closeable;
import java.sql.Array;
import java.sql.Blob;
import java.sql.CallableStatement;
@ -21,12 +22,13 @@ import java.util.Map;
import java.util.Properties;
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 String url, user, password;
private final long timeout = 60000;
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 {
Class.forName("com.mysql.jdbc.Driver");
@ -45,10 +47,8 @@ public class ConnectionPool {
if (conn.lease()) {
if (conn.isValid())
return conn;
else {
connections.remove(conn);
conn.terminate();
}
connections.remove(conn);
conn.terminate();
}
}
conn = new JDCConnection(DriverManager.getConnection(url, user, password));
@ -62,13 +62,14 @@ public class ConnectionPool {
}
private synchronized void reapConnections() {
final long stale = System.currentTimeMillis() - timeout;
final long stale = System.currentTimeMillis() - timeToLive;
for (final JDCConnection conn : connections)
if (conn.inUse() && stale > conn.getLastUse() && !conn.isValid())
connections.remove(conn);
}
}
public synchronized void closeConnections() {
@Override
public synchronized void close() {
final Enumeration<JDCConnection> conns = connections.elements();
while (conns.hasMoreElements()) {
final JDCConnection conn = conns.nextElement();
@ -102,28 +103,9 @@ public class ConnectionPool {
timestamp = 0;
}
public void terminate() {
try {
conn.close();
} 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
public void clearWarnings() throws SQLException {
conn.clearWarnings();
}
@Override
@ -131,103 +113,18 @@ public class ConnectionPool {
inuse = false;
try {
if (!conn.getAutoCommit())
conn.setAutoCommit(true);
} catch (SQLException ex) {
conn.setAutoCommit(true);
} catch (final SQLException ex) {
connections.remove(conn);
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
public void commit() throws SQLException {
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
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
return conn.createArrayOf(typeName, elements);
@ -253,6 +150,11 @@ public class ConnectionPool {
return conn.createSQLXML();
}
@Override
public Statement createStatement() throws SQLException {
return conn.createStatement();
}
@Override
public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.createStatement(resultSetType, resultSetConcurrency);
@ -268,6 +170,16 @@ public class ConnectionPool {
return conn.createStruct(typeName, attributes);
}
@Override
public boolean getAutoCommit() throws SQLException {
return conn.getAutoCommit();
}
@Override
public String getCatalog() throws SQLException {
return conn.getCatalog();
}
@Override
public Properties getClientInfo() throws SQLException {
return conn.getClientInfo();
@ -283,11 +195,44 @@ public class ConnectionPool {
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
public Map<String, Class<?>> getTypeMap() throws SQLException {
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() {
try {
return conn.isValid(1);
@ -301,6 +246,29 @@ public class ConnectionPool {
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
public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.prepareCall(sql, resultSetType, resultSetConcurrency);
@ -311,21 +279,16 @@ public class ConnectionPool {
return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
}
@Override
public PreparedStatement prepareStatement(String sql) throws SQLException {
return conn.prepareStatement(sql);
}
@Override
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException {
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
public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException {
return conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
@ -336,16 +299,41 @@ public class ConnectionPool {
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
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
conn.releaseSavepoint(savepoint);
}
@Override
public void rollback() throws SQLException {
conn.rollback();
}
@Override
public void rollback(Savepoint savepoint) throws SQLException {
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
public void setClientInfo(Properties properties) throws SQLClientInfoException {
conn.setClientInfo(properties);
@ -361,6 +349,11 @@ public class ConnectionPool {
conn.setHoldability(holdability);
}
@Override
public void setReadOnly(boolean readOnly) throws SQLException {
conn.setReadOnly(readOnly);
}
@Override
public Savepoint setSavepoint() throws SQLException {
return conn.setSavepoint();
@ -371,14 +364,20 @@ public class ConnectionPool {
return conn.setSavepoint(name);
}
@Override
public void setTransactionIsolation(int level) throws SQLException {
conn.setTransactionIsolation(level);
}
@Override
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
conn.setTypeMap(map);
}
@Override
public boolean isWrapperFor(Class<?> iface) throws SQLException {
return conn.isWrapperFor(iface);
public void terminate() {
try {
conn.close();
} catch (final SQLException ex) {}
}
@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
version: 0.15b
version: '1.00rc1'
author: DiddiZ, bootswithdefer
website: http://www.diddiz.de/minecraft/
main: de.diddiz.LogBlock.LogBlock