forked from LogBlock/LogBlock
v0.1
This commit is contained in:
38
.gitignore
vendored
38
.gitignore
vendored
@@ -1,34 +1,4 @@
|
|||||||
# Compiled source #
|
/.classpath
|
||||||
###################
|
/.project
|
||||||
*.com
|
/.settings
|
||||||
*.class
|
/bin
|
||||||
*.dll
|
|
||||||
*.exe
|
|
||||||
*.o
|
|
||||||
*.so
|
|
||||||
*.gpj
|
|
||||||
|
|
||||||
# Packages #
|
|
||||||
############
|
|
||||||
# it's better to unpack these files and commit the raw source
|
|
||||||
# git has its own built in compression methods
|
|
||||||
*.7z
|
|
||||||
*.dmg
|
|
||||||
*.gz
|
|
||||||
*.iso
|
|
||||||
*.rar
|
|
||||||
*.tar
|
|
||||||
*.zip
|
|
||||||
|
|
||||||
# Logs and databases #
|
|
||||||
######################
|
|
||||||
*.log
|
|
||||||
*.sql
|
|
||||||
*.sqlite
|
|
||||||
|
|
||||||
# OS generated files #
|
|
||||||
######################
|
|
||||||
.DS_Store?
|
|
||||||
ehthumbs.db
|
|
||||||
Icon?
|
|
||||||
Thumbs.db
|
|
BIN
LogBlock.jar
BIN
LogBlock.jar
Binary file not shown.
549
LogBlock.java
549
LogBlock.java
@@ -1,549 +0,0 @@
|
|||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
|
|
||||||
import java.util.logging.*;
|
|
||||||
import java.sql.*;
|
|
||||||
import java.io.*;
|
|
||||||
|
|
||||||
import net.minecraft.server.MinecraftServer;
|
|
||||||
|
|
||||||
public class LogBlock extends Plugin
|
|
||||||
{
|
|
||||||
private static String name = "LogBlock";
|
|
||||||
private static int version = 14;
|
|
||||||
private boolean debug = false;
|
|
||||||
private String dbDriver = "com.mysql.jdbc.Driver";
|
|
||||||
private String dbUrl = "";
|
|
||||||
private String dbUsername = "";
|
|
||||||
private String dbPassword = "";
|
|
||||||
private boolean usehModDb = false;
|
|
||||||
private int delay = 10;
|
|
||||||
private int defaultDist = 20;
|
|
||||||
private int toolID = 270; // 270 is wood pick axe
|
|
||||||
private int toolblockID = 7; // 78 is adminium
|
|
||||||
private boolean toolblockRemove = true;
|
|
||||||
private Consumer consumer = null;
|
|
||||||
private Block lastface = null;
|
|
||||||
|
|
||||||
private LinkedBlockingQueue<BlockRow> bqueue = new LinkedBlockingQueue<BlockRow>();
|
|
||||||
|
|
||||||
static final Logger log = Logger.getLogger("Minecraft");
|
|
||||||
|
|
||||||
static final Logger lblog = Logger.getLogger(name);
|
|
||||||
|
|
||||||
public void enable()
|
|
||||||
{
|
|
||||||
new VersionCheck(name, version);
|
|
||||||
|
|
||||||
PropertiesFile properties = new PropertiesFile("logblock.properties");
|
|
||||||
try {
|
|
||||||
debug = properties.getBoolean("debug", false);
|
|
||||||
usehModDb = properties.getBoolean("use-hmod-db", false);
|
|
||||||
dbDriver = properties.getString("driver", "com.mysql.jdbc.Driver");
|
|
||||||
dbUrl = properties.getString("url", "jdbc:mysql://localhost:3306/db");
|
|
||||||
dbUsername = properties.getString("username", "user");
|
|
||||||
dbPassword = properties.getString("password", "pass");
|
|
||||||
delay = properties.getInt("delay", 6);
|
|
||||||
toolID = properties.getInt("tool-id", 270);
|
|
||||||
toolblockID = properties.getInt("tool-block-id", 7);
|
|
||||||
toolblockRemove = properties.getBoolean("tool-block-remove", true);
|
|
||||||
defaultDist = properties.getInt("default-distance", 20);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
log.log(Level.SEVERE, name + ": exception while reading from logblock.properties", ex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
if (!usehModDb)
|
|
||||||
new JDCConnectionDriver(dbDriver, dbUrl, dbUsername, dbPassword);
|
|
||||||
} catch (Exception ex) {
|
|
||||||
log.log(Level.SEVERE, name + ": exception while creation database connection pool", ex);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!checkTables())
|
|
||||||
{
|
|
||||||
log.log(Level.SEVERE, name + ": errors while loading, check logs for more information.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
consumer = new Consumer();
|
|
||||||
new Thread(consumer).start();
|
|
||||||
etc.getInstance().addCommand("/lb", " - LogBlock display command.");
|
|
||||||
etc.getInstance().addCommand("/rollback", " - LogBlock Rollback command.");
|
|
||||||
log.info(name + " v" + version + " Plugin Enabled.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void disable()
|
|
||||||
{
|
|
||||||
if (consumer != null)
|
|
||||||
consumer.stop();
|
|
||||||
consumer = null;
|
|
||||||
etc.getInstance().removeCommand("/lb");
|
|
||||||
etc.getInstance().removeCommand("/rollback");
|
|
||||||
log.info(name + " v" + version + " Plugin Disabled.");
|
|
||||||
}
|
|
||||||
|
|
||||||
public void initialize()
|
|
||||||
{
|
|
||||||
try {
|
|
||||||
FileHandler lbfh = new FileHandler(name + ".log", true);
|
|
||||||
lbfh.setFormatter(new LogFormatter());
|
|
||||||
lblog.addHandler(lbfh);
|
|
||||||
} catch (IOException ex) {
|
|
||||||
log.info(name + " unable to create logger");
|
|
||||||
}
|
|
||||||
|
|
||||||
LBListener listener = new LBListener();
|
|
||||||
etc.getLoader().addListener(PluginLoader.Hook.COMMAND, listener, this, PluginListener.Priority.LOW);
|
|
||||||
etc.getLoader().addListener(PluginLoader.Hook.BLOCK_RIGHTCLICKED, listener, this, PluginListener.Priority.LOW);
|
|
||||||
etc.getLoader().addListener(PluginLoader.Hook.BLOCK_PLACE, listener, this, PluginListener.Priority.LOW);
|
|
||||||
etc.getLoader().addListener(PluginLoader.Hook.BLOCK_BROKEN, listener, this, PluginListener.Priority.LOW);
|
|
||||||
etc.getLoader().addListener(PluginLoader.Hook.SIGN_CHANGE, listener, this, PluginListener.Priority.LOW);
|
|
||||||
etc.getLoader().addListener(PluginLoader.Hook.ITEM_USE, listener, this, PluginListener.Priority.LOW);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Connection getConnection() throws SQLException
|
|
||||||
{
|
|
||||||
if (usehModDb)
|
|
||||||
return etc.getSQLConnection();
|
|
||||||
return DriverManager.getConnection("jdbc:jdc:jdcpool");
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean checkTables()
|
|
||||||
{
|
|
||||||
Connection conn = null;
|
|
||||||
ResultSet rs = null;
|
|
||||||
try {
|
|
||||||
conn = getConnection();
|
|
||||||
DatabaseMetaData dbm = conn.getMetaData();
|
|
||||||
rs = dbm.getTables(null, null, "blocks", null);
|
|
||||||
if (!rs.next())
|
|
||||||
{
|
|
||||||
log.log(Level.SEVERE, name + " blocks table doesn't exist.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
rs = dbm.getTables(null, null, "extra", null);
|
|
||||||
if (!rs.next())
|
|
||||||
{
|
|
||||||
log.log(Level.SEVERE, name + " extra table doesn't exist.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
log.log(Level.SEVERE, name + " SQL exception", ex);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (rs != null)
|
|
||||||
rs.close();
|
|
||||||
if (conn != null)
|
|
||||||
conn.close();
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
log.log(Level.SEVERE, name + " SQL exception on close", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showBlockHistory(Player player, Block b)
|
|
||||||
{
|
|
||||||
player.sendMessage(Colors.Blue + "Block history (" + b.getX() + ", " + b.getY() + ", " + b.getZ() + "): ");
|
|
||||||
boolean hist = false;
|
|
||||||
Connection conn = null;
|
|
||||||
PreparedStatement ps = null;
|
|
||||||
ResultSet rs = null;
|
|
||||||
Timestamp date;
|
|
||||||
SimpleDateFormat formatter = new SimpleDateFormat("MM-dd hh:mm:ss");
|
|
||||||
|
|
||||||
try {
|
|
||||||
conn = getConnection();
|
|
||||||
conn.setAutoCommit(false);
|
|
||||||
ps = conn.prepareStatement("SELECT * from blocks left join extra using (id) where y = ? and x = ? and z = ? order by date desc limit 10", Statement.RETURN_GENERATED_KEYS);
|
|
||||||
ps.setInt(1, b.getY());
|
|
||||||
ps.setInt(2, b.getX());
|
|
||||||
ps.setInt(3, b.getZ());
|
|
||||||
rs = ps.executeQuery();
|
|
||||||
while (rs.next())
|
|
||||||
{
|
|
||||||
date = rs.getTimestamp("date");
|
|
||||||
String datestr = formatter.format(date);
|
|
||||||
String msg = datestr + " " + rs.getString("player") + " ";
|
|
||||||
if (rs.getInt("type") == 0)
|
|
||||||
msg = msg + "destroyed " + etc.getDataSource().getItem(rs.getInt("replaced"));
|
|
||||||
else if (rs.getInt("replaced") == 0)
|
|
||||||
{
|
|
||||||
if (rs.getInt("type") == 323) // sign
|
|
||||||
msg = msg + "created " + rs.getString("extra");
|
|
||||||
else
|
|
||||||
msg = msg + "created " + etc.getDataSource().getItem(rs.getInt("type"));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
msg = msg + "replaced " + etc.getDataSource().getItem(rs.getInt("replaced")) + " with " + etc.getDataSource().getItem(rs.getInt("type"));
|
|
||||||
player.sendMessage(Colors.Gold + msg);
|
|
||||||
hist = true;
|
|
||||||
}
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
log.log(Level.SEVERE, name + " SQL exception", ex);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (rs != null)
|
|
||||||
rs.close();
|
|
||||||
if (ps != null)
|
|
||||||
ps.close();
|
|
||||||
if (conn != null)
|
|
||||||
conn.close();
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
log.log(Level.SEVERE, name + " SQL exception on close", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!hist)
|
|
||||||
player.sendMessage(Colors.Blue + "None.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void queueBlock(Player player, Block before, Block after)
|
|
||||||
{
|
|
||||||
Block b = null;
|
|
||||||
int typeA = 0;
|
|
||||||
int typeB = 0;
|
|
||||||
if (after != null)
|
|
||||||
{
|
|
||||||
typeA = after.getType();
|
|
||||||
b = after;
|
|
||||||
}
|
|
||||||
if (before != null)
|
|
||||||
{
|
|
||||||
typeB = before.getType();
|
|
||||||
b = before;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (b == null || typeA < 0 || typeB < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
BlockRow row = new BlockRow(player.getName(), typeB, typeA, b.getX(), b.getY(), b.getZ());
|
|
||||||
boolean result = bqueue.offer(row);
|
|
||||||
if (debug)
|
|
||||||
lblog.info(row.toString());
|
|
||||||
if (!result)
|
|
||||||
log.info(name + " failed to queue block for " + player.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void queueSign(Player player, Sign sign)
|
|
||||||
{
|
|
||||||
int type = etc.getDataSource().getItem("sign");
|
|
||||||
BlockRow row = new BlockRow(player.getName(), 0, type, sign.getX(), sign.getY(), sign.getZ());
|
|
||||||
|
|
||||||
String text = "sign";
|
|
||||||
for (int i=0; i < 4; i++)
|
|
||||||
text = text + " [" + sign.getText(i) + "]";
|
|
||||||
row.addExtra(text);
|
|
||||||
|
|
||||||
boolean result = bqueue.offer(row);
|
|
||||||
if (debug)
|
|
||||||
lblog.info(row.toString());
|
|
||||||
if (!result)
|
|
||||||
log.info(name + " failed to queue block for " + player.getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
private int parseTimeSpec(String ts)
|
|
||||||
{
|
|
||||||
String[] split = ts.split(" ");
|
|
||||||
|
|
||||||
if (split.length < 2)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
int min;
|
|
||||||
try {
|
|
||||||
min = Integer.parseInt(split[0]);
|
|
||||||
} catch (NumberFormatException ex) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (split[1].startsWith("hour"))
|
|
||||||
min *= 60;
|
|
||||||
else if (split[1].startsWith("day"))
|
|
||||||
min *= (60*24);
|
|
||||||
|
|
||||||
return min;
|
|
||||||
}
|
|
||||||
|
|
||||||
public class LBListener extends PluginListener // start
|
|
||||||
{
|
|
||||||
public boolean onCommand(Player player, String[] split)
|
|
||||||
{
|
|
||||||
if (!player.canUseCommand(split[0]))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (split[0].equalsIgnoreCase("/lb"))
|
|
||||||
{
|
|
||||||
Connection conn;
|
|
||||||
try {
|
|
||||||
conn = getConnection();
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
log.log(Level.SEVERE, name + " SQL exception", ex);
|
|
||||||
player.sendMessage(Colors.Rose + "Error, check server logs.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (split.length == 1) {
|
|
||||||
AreaStats th = new AreaStats(conn, player, defaultDist);
|
|
||||||
new Thread(th).start();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (split.length == 2) {
|
|
||||||
if (split[1].equalsIgnoreCase("world")) {
|
|
||||||
PlayerWorldStats th = new PlayerWorldStats(conn, player);
|
|
||||||
new Thread(th).start();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
player.sendMessage(Colors.Rose + "Incorrect usage.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (split[1].equalsIgnoreCase("player")) {
|
|
||||||
PlayerAreaStats th = new PlayerAreaStats(conn, player, split[2], defaultDist);
|
|
||||||
new Thread(th).start();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (split[1].equalsIgnoreCase("area")) {
|
|
||||||
AreaStats th = new AreaStats(conn, player, Integer.parseInt(split[2]));
|
|
||||||
new Thread(th).start();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (split[1].equalsIgnoreCase("block")) {
|
|
||||||
int type = etc.getDataSource().getItem(split[2]);
|
|
||||||
AreaBlockSearch th = new AreaBlockSearch(conn, player, type, defaultDist);
|
|
||||||
new Thread(th).start();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
player.sendMessage(Colors.Rose + "Incorrect usage.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (split[0].equalsIgnoreCase("/rollback"))
|
|
||||||
{
|
|
||||||
int minutes;
|
|
||||||
String name;
|
|
||||||
|
|
||||||
if (split.length < 3)
|
|
||||||
{
|
|
||||||
player.sendMessage(Colors.Rose + "Usate: /rollback [player] [time spec]");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
name = split[1];
|
|
||||||
minutes = parseTimeSpec(etc.combineSplit(2, split, " "));
|
|
||||||
|
|
||||||
player.sendMessage(Colors.Rose + "Rolling back " + name + " by " + minutes + " minutes.");
|
|
||||||
|
|
||||||
Connection conn;
|
|
||||||
try {
|
|
||||||
conn = getConnection();
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
log.log(Level.SEVERE, name + " SQL exception", ex);
|
|
||||||
player.sendMessage(Colors.Rose + "Error, check server logs.");
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
Rollback rb = new Rollback(conn, name, minutes);
|
|
||||||
|
|
||||||
player.sendMessage(Colors.Rose + "Edit count: " + rb.count());
|
|
||||||
|
|
||||||
new Thread(rb).start();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onBlockRightClicked(Player player, Block blockClicked, Item item)
|
|
||||||
{
|
|
||||||
if (item.getItemId() == toolID && player.canUseCommand("/blockhistory"))
|
|
||||||
{
|
|
||||||
showBlockHistory(player, blockClicked);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
lastface = blockClicked.getFace(blockClicked.getFaceClicked());
|
|
||||||
if (debug)
|
|
||||||
lblog.info("onBlockRightClicked: clicked " + blockClicked.getType() + " item " + item.getItemId() + " face " + blockClicked.getFace(blockClicked.getFaceClicked()).getType());
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onBlockPlace(Player player, Block blockPlaced, Block blockClicked, Item itemInHand)
|
|
||||||
{
|
|
||||||
if (itemInHand.getItemId() == toolblockID && player.canUseCommand("/blockhistory"))
|
|
||||||
{
|
|
||||||
showBlockHistory(player, blockPlaced);
|
|
||||||
if (toolblockRemove)
|
|
||||||
return true;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (debug)
|
|
||||||
lblog.info("onBlockPlace: placed " + blockPlaced.getType() + " clicked " + blockClicked.getType() + " item " + itemInHand.getItemId());
|
|
||||||
|
|
||||||
queueBlock(player, lastface, blockPlaced);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onBlockBreak(Player player, Block block)
|
|
||||||
{
|
|
||||||
queueBlock(player, block, null);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onSignChange(Player player, Sign sign)
|
|
||||||
{
|
|
||||||
queueSign(player, sign);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean onItemUse(Player player, Block blockPlaced, Block blockClicked, Item item)
|
|
||||||
{
|
|
||||||
if (item.getItemId() != 326 && item.getItemId() != 327) // water and lava buckets
|
|
||||||
return false;
|
|
||||||
|
|
||||||
queueBlock(player, lastface, blockPlaced);
|
|
||||||
if (debug)
|
|
||||||
lblog.info("onItemUse: placed " + blockPlaced.getType() + " clicked " + blockClicked.getType() + " item " + item.getItemId());
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} // end LBListener
|
|
||||||
|
|
||||||
private class Consumer implements Runnable // start
|
|
||||||
{
|
|
||||||
private boolean stop = false;
|
|
||||||
Consumer() { stop = false; }
|
|
||||||
public void stop() { stop = true; }
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
PreparedStatement ps = null;
|
|
||||||
Connection conn = null;
|
|
||||||
BlockRow b;
|
|
||||||
|
|
||||||
while (!stop)
|
|
||||||
{
|
|
||||||
long start = System.currentTimeMillis()/1000L;
|
|
||||||
int count = 0;
|
|
||||||
|
|
||||||
if (bqueue.size() > 100)
|
|
||||||
log.info(name + " queue size " + bqueue.size());
|
|
||||||
|
|
||||||
// if (debug)
|
|
||||||
// lblog.info("Running DB thread at " + start);
|
|
||||||
|
|
||||||
try {
|
|
||||||
conn = getConnection();
|
|
||||||
conn.setAutoCommit(false);
|
|
||||||
while (count < 100 && start+delay > (System.currentTimeMillis()/1000L))
|
|
||||||
{
|
|
||||||
// if (debug)
|
|
||||||
// lblog.info("Loop DB thread at " + (System.currentTimeMillis()/1000L));
|
|
||||||
|
|
||||||
b = bqueue.poll(1L, TimeUnit.SECONDS);
|
|
||||||
|
|
||||||
if (b == null)
|
|
||||||
continue;
|
|
||||||
//b.log();
|
|
||||||
ps = conn.prepareStatement("INSERT INTO blocks (date, player, replaced, type, x, y, z) VALUES (now(),?,?,?,?,?,?)", Statement.RETURN_GENERATED_KEYS);
|
|
||||||
ps.setString(1, b.name);
|
|
||||||
ps.setInt(2, b.replaced);
|
|
||||||
ps.setInt(3, b.type);
|
|
||||||
ps.setInt(4, b.x);
|
|
||||||
ps.setInt(5, b.y);
|
|
||||||
ps.setInt(6, b.z);
|
|
||||||
ps.executeUpdate();
|
|
||||||
|
|
||||||
if (b.extra != null)
|
|
||||||
{
|
|
||||||
ResultSet keys = ps.getGeneratedKeys();
|
|
||||||
keys.next();
|
|
||||||
int key = keys.getInt(1);
|
|
||||||
|
|
||||||
ps = conn.prepareStatement("INSERT INTO extra (id, extra) values (?,?)");
|
|
||||||
ps.setInt(1, key);
|
|
||||||
ps.setString(2, b.extra);
|
|
||||||
ps.executeUpdate();
|
|
||||||
}
|
|
||||||
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
if (debug && count > 0)
|
|
||||||
lblog.info("Commiting " + count + " inserts.");
|
|
||||||
conn.commit();
|
|
||||||
} catch (InterruptedException ex) {
|
|
||||||
log.log(Level.SEVERE, name + " interrupted exception", ex);
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
log.log(Level.SEVERE, name + " SQL exception", ex);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (ps != null)
|
|
||||||
ps.close();
|
|
||||||
if (conn != null)
|
|
||||||
conn.close();
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
log.log(Level.SEVERE, name + " SQL exception on close", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // end LBDB
|
|
||||||
|
|
||||||
private class BlockRow // start
|
|
||||||
{
|
|
||||||
public String name;
|
|
||||||
public int replaced, type;
|
|
||||||
public int x, y, z;
|
|
||||||
public String extra;
|
|
||||||
|
|
||||||
BlockRow(String name, int replaced, int type, int x, int y, int z)
|
|
||||||
{
|
|
||||||
this.name = name;
|
|
||||||
this.replaced = replaced;
|
|
||||||
this.type = type;
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.z = z;
|
|
||||||
this.extra = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addExtra(String extra)
|
|
||||||
{
|
|
||||||
this.extra = extra;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return("name: " + name + " before type: " + replaced + " type: " + type + " x: " + x + " y: " + y + " z: " + z);
|
|
||||||
}
|
|
||||||
} // end BlockRow
|
|
||||||
|
|
||||||
private class Result // start
|
|
||||||
{
|
|
||||||
public String player;
|
|
||||||
public int created;
|
|
||||||
public int destroyed;
|
|
||||||
|
|
||||||
Result(String player, int c, int d)
|
|
||||||
{
|
|
||||||
this.player = player;
|
|
||||||
this.created = c;
|
|
||||||
this.destroyed = d;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String toString()
|
|
||||||
{
|
|
||||||
return(String.format("%-6d %-6d %s", created, destroyed, player));
|
|
||||||
}
|
|
||||||
} // end Result
|
|
||||||
|
|
||||||
private class LogFormatter extends Formatter //start
|
|
||||||
{
|
|
||||||
public String format(LogRecord rec)
|
|
||||||
{
|
|
||||||
return formatMessage(rec) + "\n";
|
|
||||||
}
|
|
||||||
} // end LogFormatter
|
|
||||||
} // end LogBlock
|
|
3
MANIFEST.MF
Normal file
3
MANIFEST.MF
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
Manifest-Version: 1.0
|
||||||
|
Class-Path: ../mysql-connector-java-bin.jar
|
||||||
|
|
6
README
6
README
@@ -1,4 +1,2 @@
|
|||||||
See http://forum.hey0.net for information about these plugins.
|
This plugin logs block creates and destroys to a MySQL database. It can be used as an anti-griefing tool to find out who made a particular edit, or even roll back changes by certain players.
|
||||||
|
Originally written by bootswithdefer for hMod ported to Bukkit by me, because of impossibleness to identfy griefers. Due to BigBrother also did't work, I was forced to do it myself. The honor belongs to bootswithdefer for the sourcecode, I only spended nearly 8 hours to transcribe. All functions except sign text logging shold work as in hMod. The use of permissions plugin is possible, but not necessary.
|
||||||
To compile some packages are required (VersionCheck, JDBCPool)
|
|
||||||
that are available here: https://github.com/bootswithdefer/boots-plugins/
|
|
@@ -1,98 +0,0 @@
|
|||||||
import java.util.concurrent.LinkedBlockingQueue;
|
|
||||||
|
|
||||||
import java.util.logging.*;
|
|
||||||
import java.sql.*;
|
|
||||||
|
|
||||||
public class Rollback implements Runnable
|
|
||||||
{
|
|
||||||
static final Logger log = Logger.getLogger("Minecraft");
|
|
||||||
private LinkedBlockingQueue<Edit> edits = new LinkedBlockingQueue<Edit>();
|
|
||||||
|
|
||||||
Rollback(Connection conn, String name, int minutes)
|
|
||||||
{
|
|
||||||
String query = "select type, replaced, x, y, z from blocks where player = ? and date > date_sub(now(), interval ? minute) order by date desc";
|
|
||||||
PreparedStatement ps = null;
|
|
||||||
ResultSet rs = null;
|
|
||||||
edits.clear();
|
|
||||||
|
|
||||||
try {
|
|
||||||
conn.setAutoCommit(false);
|
|
||||||
ps = conn.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
|
|
||||||
ps.setString(1, name);
|
|
||||||
ps.setInt(2, minutes);
|
|
||||||
rs = ps.executeQuery();
|
|
||||||
|
|
||||||
while (rs.next())
|
|
||||||
{
|
|
||||||
Edit e = new Edit(rs.getInt("type"), rs.getInt("replaced"), rs.getInt("x"), rs.getInt("y"), rs.getInt("z"));
|
|
||||||
edits.offer(e);
|
|
||||||
}
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
log.log(Level.SEVERE, this.getClass().getName() + " SQL exception", ex);
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (rs != null)
|
|
||||||
rs.close();
|
|
||||||
if (ps != null)
|
|
||||||
ps.close();
|
|
||||||
if (conn != null)
|
|
||||||
conn.close();
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
log.log(Level.SEVERE, this.getClass().getName() + " SQL exception on close", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
public int count()
|
|
||||||
{
|
|
||||||
return edits.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void run()
|
|
||||||
{
|
|
||||||
Edit e = edits.poll();
|
|
||||||
|
|
||||||
while (e != null)
|
|
||||||
{
|
|
||||||
e.perform();
|
|
||||||
e.log();
|
|
||||||
e = edits.poll();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private class Edit
|
|
||||||
{
|
|
||||||
int type, replaced;
|
|
||||||
int x, y, z;
|
|
||||||
|
|
||||||
Edit(int type, int replaced, int x, int y, int z)
|
|
||||||
{
|
|
||||||
this.type = type;
|
|
||||||
this.replaced = replaced;
|
|
||||||
this.x = x;
|
|
||||||
this.y = y;
|
|
||||||
this.z = z;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void perform()
|
|
||||||
{
|
|
||||||
if (etc.getServer().getBlockIdAt(x, y, z) == type)
|
|
||||||
{
|
|
||||||
if (etc.getServer().setBlockAt(replaced, x, y, z))
|
|
||||||
log.info("R (" + x + ", " + y + ", " + z + ") " + replaced + " " + type);
|
|
||||||
else
|
|
||||||
log.info("r (" + x + ", " + y + ", " + z + ") " + replaced + " " + type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void log()
|
|
||||||
{
|
|
||||||
int current = etc.getServer().getBlockIdAt(x, y, z);
|
|
||||||
if (current == type)
|
|
||||||
log.info("+ (" + x + ", " + y + ", " + z + ") " + replaced + " " + type);
|
|
||||||
else
|
|
||||||
log.info("- (" + x + ", " + y + ", " + z + ") " + replaced + " " + type);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
21
schema.sql
21
schema.sql
@@ -1,21 +0,0 @@
|
|||||||
CREATE TABLE `blocks` (
|
|
||||||
`id` int(11) NOT NULL AUTO_INCREMENT,
|
|
||||||
`date` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
|
|
||||||
`player` varchar(32) NOT NULL DEFAULT '-',
|
|
||||||
`replaced` int(11) NOT NULL DEFAULT '0',
|
|
||||||
`type` int(11) NOT NULL DEFAULT '0',
|
|
||||||
`x` int(11) NOT NULL DEFAULT '0',
|
|
||||||
`y` int(11) NOT NULL DEFAULT '0',
|
|
||||||
`z` int(11) NOT NULL DEFAULT '0',
|
|
||||||
PRIMARY KEY (`id`),
|
|
||||||
KEY `coords` (`y`,`x`,`z`),
|
|
||||||
KEY `type` (`type`),
|
|
||||||
KEY `replaced` (`replaced`),
|
|
||||||
KEY `player` (`player`)
|
|
||||||
);
|
|
||||||
|
|
||||||
CREATE TABLE `extra` (
|
|
||||||
`id` int(11) NOT NULL,
|
|
||||||
`extra` text,
|
|
||||||
PRIMARY KEY (`id`)
|
|
||||||
);
|
|
104
src/com/bukkit/bootswithdefer/JDCBPool/ConnectionService.java
Normal file
104
src/com/bukkit/bootswithdefer/JDCBPool/ConnectionService.java
Normal file
@@ -0,0 +1,104 @@
|
|||||||
|
package com.bukkit.bootswithdefer.JDCBPool;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Enumeration;
|
||||||
|
import java.util.Vector;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>Purpose:</b>Realizes a connection pool for all JDBC connections.<br>
|
||||||
|
* <b>Description:</b>http://java.sun.com/developer/onlineTraining/Programming/JDCBook/
|
||||||
|
* conpool.html<br>
|
||||||
|
* <b>Copyright:</b>Licensed under the Apache License, Version 2.0.
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0<br>
|
||||||
|
* <b>Company:</b>SIMPL<br>
|
||||||
|
*
|
||||||
|
* @author schneimi
|
||||||
|
* @version $Id$<br>
|
||||||
|
* @link http://code.google.com/p/simpl09/
|
||||||
|
*/
|
||||||
|
public class ConnectionService {
|
||||||
|
private Vector<JDCConnection> connections;
|
||||||
|
private String url, user, password;
|
||||||
|
final private long timeout = 60000;
|
||||||
|
private ConnectionReaper reaper;
|
||||||
|
final private int poolsize = 10;
|
||||||
|
|
||||||
|
public ConnectionService(String url, String user, String password) {
|
||||||
|
this.url = url;
|
||||||
|
this.user = user;
|
||||||
|
this.password = password;
|
||||||
|
connections = new Vector<JDCConnection>(poolsize);
|
||||||
|
reaper = new ConnectionReaper(this);
|
||||||
|
reaper.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void reapConnections() {
|
||||||
|
long stale = System.currentTimeMillis() - timeout;
|
||||||
|
Enumeration<JDCConnection> connlist = connections.elements();
|
||||||
|
|
||||||
|
while ((connlist != null) && (connlist.hasMoreElements())) {
|
||||||
|
JDCConnection conn = connlist.nextElement();
|
||||||
|
|
||||||
|
if ((conn.inUse()) && (stale > conn.getLastUse()) && (!conn.validate())) {
|
||||||
|
removeConnection(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void closeConnections() {
|
||||||
|
Enumeration<JDCConnection> connlist = connections.elements();
|
||||||
|
|
||||||
|
while ((connlist != null) && (connlist.hasMoreElements())) {
|
||||||
|
JDCConnection conn = connlist.nextElement();
|
||||||
|
removeConnection(conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private synchronized void removeConnection(JDCConnection conn) {
|
||||||
|
connections.removeElement(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized Connection getConnection() throws SQLException {
|
||||||
|
JDCConnection c;
|
||||||
|
|
||||||
|
for (int i = 0; i < connections.size(); i++) {
|
||||||
|
c = connections.elementAt(i);
|
||||||
|
if (c.lease()) {
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Connection conn = DriverManager.getConnection(url, user, password);
|
||||||
|
c = new JDCConnection(conn, this);
|
||||||
|
c.lease();
|
||||||
|
connections.addElement(c);
|
||||||
|
|
||||||
|
return c.getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void returnConnection(JDCConnection conn) {
|
||||||
|
conn.expireLease();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ConnectionReaper extends Thread {
|
||||||
|
private ConnectionService pool;
|
||||||
|
private final long delay = 300000;
|
||||||
|
|
||||||
|
ConnectionReaper(ConnectionService pool) {
|
||||||
|
this.pool = pool;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
while (true) {
|
||||||
|
try {
|
||||||
|
Thread.sleep(delay);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
}
|
||||||
|
pool.reapConnections();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
455
src/com/bukkit/bootswithdefer/JDCBPool/JDCConnection.java
Normal file
455
src/com/bukkit/bootswithdefer/JDCBPool/JDCConnection.java
Normal file
@@ -0,0 +1,455 @@
|
|||||||
|
package com.bukkit.bootswithdefer.JDCBPool;
|
||||||
|
|
||||||
|
import java.sql.Array;
|
||||||
|
import java.sql.Blob;
|
||||||
|
import java.sql.CallableStatement;
|
||||||
|
import java.sql.Clob;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DatabaseMetaData;
|
||||||
|
import java.sql.NClob;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.SQLClientInfoException;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.SQLWarning;
|
||||||
|
import java.sql.SQLXML;
|
||||||
|
import java.sql.Savepoint;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.sql.Struct;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>Purpose:</b>Wrapper for JDBCConnection.<br>
|
||||||
|
* <b>Description:</b>http://java.sun.com/developer/onlineTraining/Programming/JDCBook/
|
||||||
|
* conpool.html<br>
|
||||||
|
* <b>Copyright:</b>Licensed under the Apache License, Version 2.0.
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0<br>
|
||||||
|
* <b>Company:</b>SIMPL<br>
|
||||||
|
*
|
||||||
|
* @author schneimi
|
||||||
|
* @version $Id$<br>
|
||||||
|
* @link http://code.google.com/p/simpl09/
|
||||||
|
*/
|
||||||
|
public class JDCConnection implements Connection {
|
||||||
|
private ConnectionService pool;
|
||||||
|
private Connection conn;
|
||||||
|
private boolean inuse;
|
||||||
|
private long timestamp;
|
||||||
|
|
||||||
|
public JDCConnection(Connection conn, ConnectionService pool) {
|
||||||
|
this.conn = conn;
|
||||||
|
this.pool = pool;
|
||||||
|
this.inuse = false;
|
||||||
|
this.timestamp = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized boolean lease() {
|
||||||
|
if (inuse) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
inuse = true;
|
||||||
|
timestamp = System.currentTimeMillis();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean validate() {
|
||||||
|
try {
|
||||||
|
conn.getMetaData();
|
||||||
|
} catch (Exception e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean inUse() {
|
||||||
|
return inuse;
|
||||||
|
}
|
||||||
|
|
||||||
|
public long getLastUse() {
|
||||||
|
return timestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void close() throws SQLException {
|
||||||
|
pool.returnConnection(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void expireLease() {
|
||||||
|
inuse = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected Connection getConnection() {
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
public PreparedStatement prepareStatement(String sql) throws SQLException {
|
||||||
|
return conn.prepareStatement(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public CallableStatement prepareCall(String sql) throws SQLException {
|
||||||
|
return conn.prepareCall(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Statement createStatement() throws SQLException {
|
||||||
|
return conn.createStatement();
|
||||||
|
}
|
||||||
|
|
||||||
|
public String nativeSQL(String sql) throws SQLException {
|
||||||
|
return conn.nativeSQL(sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setAutoCommit(boolean autoCommit) throws SQLException {
|
||||||
|
conn.setAutoCommit(autoCommit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean getAutoCommit() throws SQLException {
|
||||||
|
return conn.getAutoCommit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void commit() throws SQLException {
|
||||||
|
conn.commit();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void rollback() throws SQLException {
|
||||||
|
conn.rollback();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isClosed() throws SQLException {
|
||||||
|
return conn.isClosed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DatabaseMetaData getMetaData() throws SQLException {
|
||||||
|
return conn.getMetaData();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setReadOnly(boolean readOnly) throws SQLException {
|
||||||
|
conn.setReadOnly(readOnly);
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isReadOnly() throws SQLException {
|
||||||
|
return conn.isReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCatalog(String catalog) throws SQLException {
|
||||||
|
conn.setCatalog(catalog);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getCatalog() throws SQLException {
|
||||||
|
return conn.getCatalog();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTransactionIsolation(int level) throws SQLException {
|
||||||
|
conn.setTransactionIsolation(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getTransactionIsolation() throws SQLException {
|
||||||
|
return conn.getTransactionIsolation();
|
||||||
|
}
|
||||||
|
|
||||||
|
public SQLWarning getWarnings() throws SQLException {
|
||||||
|
return conn.getWarnings();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearWarnings() throws SQLException {
|
||||||
|
conn.clearWarnings();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#createArrayOf(java.lang.String, java.lang.Object[])
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Array createArrayOf(String typeName, Object[] elements) throws SQLException {
|
||||||
|
return conn.createArrayOf(typeName, elements);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#createBlob()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Blob createBlob() throws SQLException {
|
||||||
|
return createBlob();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#createClob()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Clob createClob() throws SQLException {
|
||||||
|
return conn.createClob();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#createNClob()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public NClob createNClob() throws SQLException {
|
||||||
|
return conn.createNClob();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#createSQLXML()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public SQLXML createSQLXML() throws SQLException {
|
||||||
|
return conn.createSQLXML();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#createStatement(int, int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Statement createStatement(int resultSetType, int resultSetConcurrency)
|
||||||
|
throws SQLException {
|
||||||
|
return conn.createStatement(resultSetType, resultSetConcurrency);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#createStatement(int, int, int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Statement createStatement(int resultSetType, int resultSetConcurrency,
|
||||||
|
int resultSetHoldability) throws SQLException {
|
||||||
|
return conn
|
||||||
|
.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#createStruct(java.lang.String, java.lang.Object[])
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Struct createStruct(String typeName, Object[] attributes) throws SQLException {
|
||||||
|
return conn.createStruct(typeName, attributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#getClientInfo()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Properties getClientInfo() throws SQLException {
|
||||||
|
return conn.getClientInfo();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#getClientInfo(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getClientInfo(String name) throws SQLException {
|
||||||
|
return conn.getClientInfo(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#getHoldability()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public int getHoldability() throws SQLException {
|
||||||
|
return conn.getHoldability();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#getTypeMap()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Map<String, Class<?>> getTypeMap() throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#isValid(int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isValid(int timeout) throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#prepareCall(java.lang.String, int, int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CallableStatement prepareCall(String sql, int resultSetType,
|
||||||
|
int resultSetConcurrency) throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#prepareCall(java.lang.String, int, int, int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public CallableStatement prepareCall(String sql, int resultSetType,
|
||||||
|
int resultSetConcurrency, int resultSetHoldability) throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#prepareStatement(java.lang.String, int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
|
||||||
|
throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#prepareStatement(java.lang.String, int[])
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
|
||||||
|
throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#prepareStatement(java.lang.String, java.lang.String[])
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public PreparedStatement prepareStatement(String sql, String[] columnNames)
|
||||||
|
throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#prepareStatement(java.lang.String, int, int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public PreparedStatement prepareStatement(String sql, int resultSetType,
|
||||||
|
int resultSetConcurrency) throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#prepareStatement(java.lang.String, int, int, int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public PreparedStatement prepareStatement(String sql, int resultSetType,
|
||||||
|
int resultSetConcurrency, int resultSetHoldability) throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#releaseSavepoint(java.sql.Savepoint)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void releaseSavepoint(Savepoint savepoint) throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#rollback(java.sql.Savepoint)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void rollback(Savepoint savepoint) throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#setClientInfo(java.util.Properties)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setClientInfo(Properties properties) throws SQLClientInfoException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#setClientInfo(java.lang.String, java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setClientInfo(String name, String value) throws SQLClientInfoException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#setHoldability(int)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setHoldability(int holdability) throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#setSavepoint()
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Savepoint setSavepoint() throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#setSavepoint(java.lang.String)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Savepoint setSavepoint(String name) throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Connection#setTypeMap(java.util.Map)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setTypeMap(Map<String, Class<?>> map) throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Wrapper#isWrapperFor(java.lang.Class)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public boolean isWrapperFor(Class<?> iface) throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* (non-Javadoc)
|
||||||
|
* @see java.sql.Wrapper#unwrap(java.lang.Class)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public <T> T unwrap(Class<T> iface) throws SQLException {
|
||||||
|
// TODO Auto-generated method stub
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,63 @@
|
|||||||
|
package com.bukkit.bootswithdefer.JDCBPool;
|
||||||
|
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.Driver;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.DriverPropertyInfo;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>Purpose:</b>Wrapper for JDBCConnectionDriver.<br>
|
||||||
|
* <b>Description:</b>http://java.sun.com/developer/onlineTraining/Programming/JDCBook/
|
||||||
|
* conpool.html<br>
|
||||||
|
* <b>Copyright:</b>Licensed under the Apache License, Version 2.0.
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0<br>
|
||||||
|
* <b>Company:</b> SIMPL<br>
|
||||||
|
*
|
||||||
|
* @author schneimi
|
||||||
|
* @version $Id: JDCConnectionDriver.java 1224 2010-04-28 14:17:34Z
|
||||||
|
* michael.schneidt@arcor.de $<br>
|
||||||
|
* @link http://code.google.com/p/simpl09/
|
||||||
|
*/
|
||||||
|
public class JDCConnectionDriver implements Driver {
|
||||||
|
public static final String URL_PREFIX = "jdbc:jdc:";
|
||||||
|
private static final int MAJOR_VERSION = 1;
|
||||||
|
private static final int MINOR_VERSION = 0;
|
||||||
|
private ConnectionService pool;
|
||||||
|
|
||||||
|
public JDCConnectionDriver(String driver, String url, String user, String password)
|
||||||
|
throws ClassNotFoundException, InstantiationException, IllegalAccessException,
|
||||||
|
SQLException {
|
||||||
|
DriverManager.registerDriver(this);
|
||||||
|
Class.forName(driver).newInstance();
|
||||||
|
pool = new ConnectionService(url, user, password);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Connection connect(String url, Properties props) throws SQLException {
|
||||||
|
if (!url.startsWith(JDCConnectionDriver.URL_PREFIX)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return pool.getConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean acceptsURL(String url) {
|
||||||
|
return url.startsWith(JDCConnectionDriver.URL_PREFIX);
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMajorVersion() {
|
||||||
|
return JDCConnectionDriver.MAJOR_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getMinorVersion() {
|
||||||
|
return JDCConnectionDriver.MINOR_VERSION;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DriverPropertyInfo[] getPropertyInfo(String str, Properties props) {
|
||||||
|
return new DriverPropertyInfo[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean jdbcCompliant() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
43
AreaBlockSearch.java → src/com/bukkit/diddiz/LogBlock/AreaBlockSearch.java
Executable file → Normal file
43
AreaBlockSearch.java → src/com/bukkit/diddiz/LogBlock/AreaBlockSearch.java
Executable file → Normal file
@@ -1,9 +1,18 @@
|
|||||||
import java.util.HashSet;
|
package com.bukkit.diddiz.LogBlock;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
|
|
||||||
import java.util.logging.*;
|
import java.sql.Connection;
|
||||||
import java.sql.*;
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.bukkit.Location;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public class AreaBlockSearch implements Runnable
|
public class AreaBlockSearch implements Runnable
|
||||||
{
|
{
|
||||||
@@ -35,15 +44,15 @@ public class AreaBlockSearch implements Runnable
|
|||||||
ps = conn.prepareStatement("SELECT * from blocks where (type = ? or replaced = ?) and y > ? and y < ? and x > ? and x < ? and z > ? and z < ? order by date desc limit 10", Statement.RETURN_GENERATED_KEYS);
|
ps = conn.prepareStatement("SELECT * from blocks where (type = ? or replaced = ?) and y > ? and y < ? and x > ? and x < ? and z > ? and z < ? order by date desc limit 10", Statement.RETURN_GENERATED_KEYS);
|
||||||
ps.setInt(1, type);
|
ps.setInt(1, type);
|
||||||
ps.setInt(2, type);
|
ps.setInt(2, type);
|
||||||
ps.setInt(3, (int)(location.y) - size);
|
ps.setInt(3, location.getBlockY() - size);
|
||||||
ps.setInt(4, (int)(location.y) + size);
|
ps.setInt(4, location.getBlockY() + size);
|
||||||
ps.setInt(5, (int)(location.x) - size);
|
ps.setInt(5, location.getBlockX() - size);
|
||||||
ps.setInt(6, (int)(location.x) + size);
|
ps.setInt(6, location.getBlockX() + size);
|
||||||
ps.setInt(7, (int)(location.z) - size);
|
ps.setInt(7, location.getBlockZ() - size);
|
||||||
ps.setInt(8, (int)(location.z) + size);
|
ps.setInt(8, location.getBlockZ() + size);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
|
|
||||||
player.sendMessage(Colors.Blue + "Block history within " + size + " blocks of " + (int)(location.x) + ", " + (int)(location.y) + ", " + (int)(location.z) + ": ");
|
player.sendMessage("§3Block history within " + size + " blocks of " + location.getBlockX() + ", " + location.getBlockY() + ", " + location.getBlockZ() + ": ");
|
||||||
|
|
||||||
while (rs.next())
|
while (rs.next())
|
||||||
{
|
{
|
||||||
@@ -51,12 +60,12 @@ public class AreaBlockSearch implements Runnable
|
|||||||
String datestr = formatter.format(date);
|
String datestr = formatter.format(date);
|
||||||
String msg = datestr + " " + rs.getString("player") + " (" + rs.getInt("x") + ", " + rs.getInt("y") + ", " + rs.getInt("z") + ") ";
|
String msg = datestr + " " + rs.getString("player") + " (" + rs.getInt("x") + ", " + rs.getInt("y") + ", " + rs.getInt("z") + ") ";
|
||||||
if (rs.getInt("type") == 0)
|
if (rs.getInt("type") == 0)
|
||||||
msg = msg + "destroyed " + etc.getDataSource().getItem(rs.getInt("replaced"));
|
msg = msg + "destroyed " + Material.getMaterial(rs.getInt("replaced")).toString().toLowerCase().replace('_', ' ');
|
||||||
else if (rs.getInt("replaced") == 0)
|
else if (rs.getInt("replaced") == 0)
|
||||||
msg = msg + "created " + etc.getDataSource().getItem(rs.getInt("type"));
|
msg = msg + "created " + Material.getMaterial(rs.getInt("type")).toString().toLowerCase().replace('_', ' ');
|
||||||
else
|
else
|
||||||
msg = msg + "replaced " + etc.getDataSource().getItem(rs.getInt("replaced")) + " with " + etc.getDataSource().getItem(rs.getInt("type"));
|
msg = msg + "replaced " + Material.getMaterial(rs.getInt("replaced")).toString().toLowerCase().replace('_', ' ') + " with " + Material.getMaterial(rs.getInt("type")).toString().toLowerCase().replace('_', ' ');
|
||||||
player.sendMessage(Colors.Gold + msg);
|
player.sendMessage("§6" + msg);
|
||||||
hist = true;
|
hist = true;
|
||||||
}
|
}
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
@@ -74,6 +83,6 @@ public class AreaBlockSearch implements Runnable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!hist)
|
if (!hist)
|
||||||
player.sendMessage(Colors.Blue + "None.");
|
player.sendMessage("§3None.");
|
||||||
}
|
}
|
||||||
}
|
}
|
48
AreaStats.java → src/com/bukkit/diddiz/LogBlock/AreaStats.java
Executable file → Normal file
48
AreaStats.java → src/com/bukkit/diddiz/LogBlock/AreaStats.java
Executable file → Normal file
@@ -1,8 +1,16 @@
|
|||||||
import java.util.HashSet;
|
package com.bukkit.diddiz.LogBlock;
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import java.util.logging.*;
|
import java.sql.Connection;
|
||||||
import java.sql.*;
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public class AreaStats implements Runnable
|
public class AreaStats implements Runnable
|
||||||
{
|
{
|
||||||
@@ -29,12 +37,12 @@ public class AreaStats implements Runnable
|
|||||||
try {
|
try {
|
||||||
conn.setAutoCommit(false);
|
conn.setAutoCommit(false);
|
||||||
ps = conn.prepareStatement("SELECT player, count(player) as num from blocks where type > 0 and y > ? and y < ? and x > ? and x < ? and z > ? and z < ? group by player order by count(player) desc limit 10", Statement.RETURN_GENERATED_KEYS);
|
ps = conn.prepareStatement("SELECT player, count(player) as num from blocks where type > 0 and y > ? and y < ? and x > ? and x < ? and z > ? and z < ? group by player order by count(player) desc limit 10", Statement.RETURN_GENERATED_KEYS);
|
||||||
ps.setInt(1, (int)player.getY()-size);
|
ps.setInt(1, player.getLocation().getBlockY()-size);
|
||||||
ps.setInt(2, (int)player.getY()+size);
|
ps.setInt(2, player.getLocation().getBlockY()+size);
|
||||||
ps.setInt(3, (int)player.getX()-size);
|
ps.setInt(3, player.getLocation().getBlockX()-size);
|
||||||
ps.setInt(4, (int)player.getX()+size);
|
ps.setInt(4, player.getLocation().getBlockX()+size);
|
||||||
ps.setInt(5, (int)player.getZ()-size);
|
ps.setInt(5, player.getLocation().getBlockZ()-size);
|
||||||
ps.setInt(6, (int)player.getZ()+size);
|
ps.setInt(6, player.getLocation().getBlockZ()+size);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
while (rs.next())
|
while (rs.next())
|
||||||
{
|
{
|
||||||
@@ -45,12 +53,12 @@ public class AreaStats implements Runnable
|
|||||||
ps.close();
|
ps.close();
|
||||||
|
|
||||||
ps = conn.prepareStatement("SELECT player, count(player) as num from blocks where replaced > 0 and y > ? and y < ? and x > ? and x < ? and z > ? and z < ? group by player order by count(player) desc limit 10", Statement.RETURN_GENERATED_KEYS);
|
ps = conn.prepareStatement("SELECT player, count(player) as num from blocks where replaced > 0 and y > ? and y < ? and x > ? and x < ? and z > ? and z < ? group by player order by count(player) desc limit 10", Statement.RETURN_GENERATED_KEYS);
|
||||||
ps.setInt(1, (int)player.getY()-size);
|
ps.setInt(1, player.getLocation().getBlockY()-size);
|
||||||
ps.setInt(2, (int)player.getY()+size);
|
ps.setInt(2, player.getLocation().getBlockY()+size);
|
||||||
ps.setInt(3, (int)player.getX()-size);
|
ps.setInt(3, player.getLocation().getBlockX()-size);
|
||||||
ps.setInt(4, (int)player.getX()+size);
|
ps.setInt(4, player.getLocation().getBlockX()+size);
|
||||||
ps.setInt(5, (int)player.getZ()-size);
|
ps.setInt(5, player.getLocation().getBlockZ()-size);
|
||||||
ps.setInt(6, (int)player.getZ()+size);
|
ps.setInt(6, player.getLocation().getBlockZ()+size);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
while (rs.next())
|
while (rs.next())
|
||||||
{
|
{
|
||||||
@@ -73,14 +81,14 @@ public class AreaStats implements Runnable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
player.sendMessage(Colors.Blue + "Within " + size + " blocks of you: ");
|
player.sendMessage("§3Within " + size + " blocks of you: ");
|
||||||
if (players.size() == 0)
|
if (players.size() == 0)
|
||||||
{
|
{
|
||||||
player.sendMessage(Colors.Blue + "No results found.");
|
player.sendMessage("§3No results found.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
player.sendMessage(Colors.Gold + String.format("%-6s %-6s %s", "Creat", "Destr", "Player"));
|
player.sendMessage("§6" + String.format("%-6s %-6s %s", "Creat", "Destr", "Player"));
|
||||||
for (String p: players)
|
for (String p: players)
|
||||||
{
|
{
|
||||||
Integer c = created.get(p);
|
Integer c = created.get(p);
|
||||||
@@ -89,7 +97,7 @@ public class AreaStats implements Runnable
|
|||||||
c = 0;
|
c = 0;
|
||||||
if (d == null)
|
if (d == null)
|
||||||
d = 0;
|
d = 0;
|
||||||
player.sendMessage(Colors.Gold + String.format("%-6d %-6d %s", c, d, p));
|
player.sendMessage("§6" + String.format("%-6d %-6d %s", c, d, p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
634
src/com/bukkit/diddiz/LogBlock/LogBlock.java
Normal file
634
src/com/bukkit/diddiz/LogBlock/LogBlock.java
Normal file
@@ -0,0 +1,634 @@
|
|||||||
|
package com.bukkit.diddiz.LogBlock;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileWriter;
|
||||||
|
import java.sql.Connection;
|
||||||
|
import java.sql.DatabaseMetaData;
|
||||||
|
import java.sql.DriverManager;
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.sql.Timestamp;
|
||||||
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.Server;
|
||||||
|
import org.bukkit.World;
|
||||||
|
import org.bukkit.block.Block;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
import org.bukkit.event.Event;
|
||||||
|
import org.bukkit.event.Event.Type;
|
||||||
|
import org.bukkit.event.block.BlockBreakEvent;
|
||||||
|
import org.bukkit.event.block.BlockListener;
|
||||||
|
import org.bukkit.event.block.BlockPlaceEvent;
|
||||||
|
import org.bukkit.event.block.BlockRightClickEvent;
|
||||||
|
import org.bukkit.event.player.PlayerChatEvent;
|
||||||
|
import org.bukkit.event.player.PlayerItemEvent;
|
||||||
|
import org.bukkit.event.player.PlayerListener;
|
||||||
|
import org.bukkit.plugin.PluginDescriptionFile;
|
||||||
|
import org.bukkit.plugin.PluginLoader;
|
||||||
|
import org.bukkit.plugin.PluginManager;
|
||||||
|
import org.bukkit.plugin.java.JavaPlugin;
|
||||||
|
|
||||||
|
import com.bukkit.bootswithdefer.JDCBPool.JDCConnectionDriver;
|
||||||
|
import com.nijikokun.bukkit.Permissions.Permissions;
|
||||||
|
|
||||||
|
public class LogBlock extends JavaPlugin
|
||||||
|
{
|
||||||
|
private LBLPlayerListener lblPlayerListener = new LBLPlayerListener();
|
||||||
|
private LBLBlockListener lblBlockListener = new LBLBlockListener();
|
||||||
|
static final Logger log = Logger.getLogger("Minecraft");
|
||||||
|
List<World> worlds = getServer().getWorlds();
|
||||||
|
private boolean usePermissions = false;
|
||||||
|
private String dbDriver = "com.mysql.jdbc.Driver";
|
||||||
|
private String dbUrl = "";
|
||||||
|
private String dbUsername = "";
|
||||||
|
private String dbPassword = "";
|
||||||
|
private String name = "[LogBlock]";
|
||||||
|
private int delay = 10;
|
||||||
|
private int defaultDist = 20;
|
||||||
|
private int toolID = 270;
|
||||||
|
private int toolblockID = 7;
|
||||||
|
private boolean toolblockRemove = true;
|
||||||
|
private Consumer consumer = null;
|
||||||
|
|
||||||
|
|
||||||
|
private LinkedBlockingQueue<BlockRow> bqueue = new LinkedBlockingQueue<BlockRow>();
|
||||||
|
|
||||||
|
public LogBlock(PluginLoader pluginLoader, Server instance, PluginDescriptionFile desc, File folder, File plugin, ClassLoader cLoader)
|
||||||
|
{
|
||||||
|
super(pluginLoader, instance, desc, folder, plugin, cLoader);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onEnable()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
File file = new File (getDataFolder(), "config.yml");
|
||||||
|
if (!file.exists())
|
||||||
|
{
|
||||||
|
file.getParentFile().mkdirs();
|
||||||
|
FileWriter writer = new FileWriter(file);
|
||||||
|
String crlf = System.getProperty("line.separator");
|
||||||
|
writer.write("driver : com.mysql.jdbc.Driver" + crlf
|
||||||
|
+ "url : jdbc:mysql://localhost:3306/db" + crlf
|
||||||
|
+ "username : user" + crlf
|
||||||
|
+ "password : pass" + crlf
|
||||||
|
+ "delay : 6" + crlf
|
||||||
|
+ "tool-id : 270" + crlf
|
||||||
|
+ "tool-block-id : 7" + crlf
|
||||||
|
+ "tool-block-remove : true" + crlf
|
||||||
|
+ "default-distance : 20" + crlf
|
||||||
|
+ "usePermissions : false");
|
||||||
|
writer.close();
|
||||||
|
log.info(name + " Config created");
|
||||||
|
}
|
||||||
|
getConfiguration().load();
|
||||||
|
dbDriver = getConfiguration().getString("driver", "com.mysql.jdbc.Driver");
|
||||||
|
dbUrl = getConfiguration().getString("url", "jdbc:mysql://localhost:3306/db");
|
||||||
|
dbUsername = getConfiguration().getString("username", "user");
|
||||||
|
dbPassword = getConfiguration().getString("password", "pass");
|
||||||
|
delay = getConfiguration().getInt("delay", 6);
|
||||||
|
toolID = getConfiguration().getInt("tool-id", 270);
|
||||||
|
toolblockID = getConfiguration().getInt("tool-block-id", 7);
|
||||||
|
toolblockRemove = getConfiguration().getBoolean("tool-block-remove", true);
|
||||||
|
defaultDist = getConfiguration().getInt("default-distance", 20);
|
||||||
|
if (getConfiguration().getBoolean("usePermissions", false))
|
||||||
|
{
|
||||||
|
if (getServer().getPluginManager().getPlugin("Permissions") != null)
|
||||||
|
{
|
||||||
|
usePermissions = true;
|
||||||
|
log.info(name + " Permissions enabled");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
log.info(name + " Permissions plugin not found. Use default permissions.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
log.log(Level.SEVERE, name + " Exception while reading config.yml", e);
|
||||||
|
getServer().getPluginManager().disablePlugin(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
new JDCConnectionDriver(dbDriver, dbUrl, dbUsername, dbPassword);
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
log.log(Level.SEVERE, name + ": exception while creation database connection pool", ex);
|
||||||
|
getServer().getPluginManager().disablePlugin(this);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!checkTables())
|
||||||
|
{
|
||||||
|
log.log(Level.SEVERE, name + " Errors while loading, check logs for more information.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PluginManager pm = getServer().getPluginManager();
|
||||||
|
pm.registerEvent(Type.PLAYER_COMMAND, lblPlayerListener, Event.Priority.Normal, this);
|
||||||
|
pm.registerEvent(Type.BLOCK_RIGHTCLICKED, lblBlockListener, Event.Priority.Monitor, this);
|
||||||
|
pm.registerEvent(Type.BLOCK_PLACED, lblBlockListener, Event.Priority.Monitor, this);
|
||||||
|
pm.registerEvent(Type.BLOCK_BREAK, lblBlockListener, Event.Priority.Monitor, this);
|
||||||
|
pm.registerEvent(Type.PLAYER_ITEM, lblPlayerListener, Event.Priority.Monitor, this);
|
||||||
|
consumer = new Consumer();
|
||||||
|
new Thread(consumer).start();
|
||||||
|
log.info(name + " v" + getDescription().getVersion() + " Plugin Enabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onDisable()
|
||||||
|
{
|
||||||
|
if (consumer != null)
|
||||||
|
{
|
||||||
|
consumer.stop();
|
||||||
|
consumer = null;
|
||||||
|
}
|
||||||
|
log.info("LogBlock disabled.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Connection getConnection() throws SQLException
|
||||||
|
{
|
||||||
|
return DriverManager.getConnection("jdbc:jdc:jdcpool");
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean checkTables()
|
||||||
|
{
|
||||||
|
Connection conn = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
try {
|
||||||
|
conn = getConnection();
|
||||||
|
DatabaseMetaData dbm = conn.getMetaData();
|
||||||
|
rs = dbm.getTables(null, null, "blocks", null);
|
||||||
|
if (!rs.next())
|
||||||
|
{
|
||||||
|
log.log(Level.SEVERE, name + " blocks table doesn't exist.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
rs = dbm.getTables(null, null, "extra", null);
|
||||||
|
if (!rs.next())
|
||||||
|
{
|
||||||
|
log.log(Level.SEVERE, name + " extra table doesn't exist.");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
log.log(Level.SEVERE, name + " SQL exception", ex);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (rs != null)
|
||||||
|
rs.close();
|
||||||
|
if (conn != null)
|
||||||
|
conn.close();
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
log.log(Level.SEVERE, name + " SQL exception on close", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showBlockHistory(Player player, Block b)
|
||||||
|
{
|
||||||
|
player.sendMessage("<EFBFBD>3Block history (" + b.getX() + ", " + b.getY() + ", " + b.getZ() + "): ");
|
||||||
|
boolean hist = false;
|
||||||
|
Connection conn = null;
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
Timestamp date;
|
||||||
|
SimpleDateFormat formatter = new SimpleDateFormat("MM-dd hh:mm:ss");
|
||||||
|
|
||||||
|
try {
|
||||||
|
conn = getConnection();
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
ps = conn.prepareStatement("SELECT * from blocks left join extra using (id) where y = ? and x = ? and z = ? order by date desc limit 10", Statement.RETURN_GENERATED_KEYS);
|
||||||
|
ps.setInt(1, b.getY());
|
||||||
|
ps.setInt(2, b.getX());
|
||||||
|
ps.setInt(3, b.getZ());
|
||||||
|
rs = ps.executeQuery();
|
||||||
|
while (rs.next())
|
||||||
|
{
|
||||||
|
date = rs.getTimestamp("date");
|
||||||
|
String datestr = formatter.format(date);
|
||||||
|
String msg = datestr + " " + rs.getString("player") + " ";
|
||||||
|
if (rs.getInt("type") == 0)
|
||||||
|
msg = msg + "destroyed " + Material.getMaterial(rs.getInt("replaced")).toString().toLowerCase().replace('_', ' ');
|
||||||
|
else if (rs.getInt("replaced") == 0)
|
||||||
|
{
|
||||||
|
if (rs.getInt("type") == 323) // sign
|
||||||
|
msg = msg + "created " + rs.getString("extra");
|
||||||
|
else
|
||||||
|
msg = msg + "created " + Material.getMaterial(rs.getInt("type")).toString().toLowerCase().replace('_', ' ');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
msg = msg + "replaced " + Material.getMaterial(rs.getInt("replaced")).toString().toLowerCase().replace('_', ' ') + " with " + Material.getMaterial(rs.getInt("type")).toString().toLowerCase().replace('_', ' ');
|
||||||
|
player.sendMessage("<EFBFBD>6" + msg);
|
||||||
|
hist = true;
|
||||||
|
}
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
log.log(Level.SEVERE, name + " SQL exception", ex);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (rs != null)
|
||||||
|
rs.close();
|
||||||
|
if (ps != null)
|
||||||
|
ps.close();
|
||||||
|
if (conn != null)
|
||||||
|
conn.close();
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
log.log(Level.SEVERE, name + " SQL exception on close", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!hist)
|
||||||
|
player.sendMessage("<EFBFBD>3None.");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void queueBlock(String playerName, Block block, int typeBefore, int typeAfter)
|
||||||
|
{
|
||||||
|
if (block == null || typeBefore < 0 || typeAfter < 0)
|
||||||
|
return;
|
||||||
|
BlockRow row = new BlockRow(playerName, typeBefore, typeAfter, block.getX(), block.getY(), block.getZ());
|
||||||
|
boolean result = bqueue.offer(row);
|
||||||
|
if (!result)
|
||||||
|
log.info(name + " failed to queue block for " + playerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
//private void queueSign(Player player, Sign sign)
|
||||||
|
//{
|
||||||
|
// int type = 63;
|
||||||
|
// BlockRow row = new BlockRow(player.getName(), 0, type, sign.getX(), sign.getY(), sign.getZ());
|
||||||
|
// String text = "sign";
|
||||||
|
// for (int i=0; i < 4; i++)
|
||||||
|
// text = text + " [" + sign.getLine(i) + "]";
|
||||||
|
// row.addExtra(text);
|
||||||
|
// boolean result = bqueue.offer(row);
|
||||||
|
// if (!result)
|
||||||
|
// log.info(name + " failed to queue block for " + player.getName());
|
||||||
|
//}
|
||||||
|
|
||||||
|
private boolean CheckPermission(Player player, String permission)
|
||||||
|
{
|
||||||
|
if (usePermissions)
|
||||||
|
return Permissions.Security.permission(player, permission);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (permission.equals("logblock.lookup"))
|
||||||
|
return true;
|
||||||
|
else if (permission.equals("logblock.area"))
|
||||||
|
return player.isOp();
|
||||||
|
else if (permission.equals("logblock.rollback"))
|
||||||
|
return player.isOp();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int parseTimeSpec(String ts)
|
||||||
|
{
|
||||||
|
String[] split = ts.split(" ");
|
||||||
|
|
||||||
|
if (split.length < 2)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
int min;
|
||||||
|
try {
|
||||||
|
min = Integer.parseInt(split[0]);
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (split[1].startsWith("hour"))
|
||||||
|
min *= 60;
|
||||||
|
else if (split[1].startsWith("day"))
|
||||||
|
min *= (60*24);
|
||||||
|
return min;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LBLPlayerListener extends PlayerListener
|
||||||
|
{
|
||||||
|
public void onPlayerCommand(PlayerChatEvent event) {
|
||||||
|
if (event.isCancelled())
|
||||||
|
return;
|
||||||
|
String[] split = event.getMessage().split(" ");
|
||||||
|
Player player = event.getPlayer();
|
||||||
|
if (split[0].equalsIgnoreCase("/lb")) {
|
||||||
|
event.setCancelled(true);
|
||||||
|
if (!CheckPermission(event.getPlayer(),"logblock.area"))
|
||||||
|
{
|
||||||
|
event.getPlayer().sendMessage("<EFBFBD>cInsufficient permissions");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Connection conn;
|
||||||
|
try {
|
||||||
|
conn = getConnection();
|
||||||
|
}
|
||||||
|
catch (SQLException ex) {
|
||||||
|
log.log(Level.SEVERE, name + " SQL exception", ex);
|
||||||
|
player.sendMessage("<EFBFBD>cError, check server logs.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (split.length == 1) {
|
||||||
|
AreaStats th = new AreaStats(conn, player, defaultDist);
|
||||||
|
new Thread(th).start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (split.length == 2) {
|
||||||
|
if (split[1].equalsIgnoreCase("world")) {
|
||||||
|
PlayerWorldStats th = new PlayerWorldStats(conn, player);
|
||||||
|
new Thread(th).start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
player.sendMessage("<EFBFBD>cIncorrect usage.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (split.length == 3) {
|
||||||
|
if (split[1].equalsIgnoreCase("player")) {
|
||||||
|
PlayerAreaStats th = new PlayerAreaStats(conn, player, split[2], defaultDist);
|
||||||
|
new Thread(th).start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (split[1].equalsIgnoreCase("area")) {
|
||||||
|
AreaStats th = new AreaStats(conn, player, Integer.parseInt(split[2]));
|
||||||
|
new Thread(th).start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (split[1].equalsIgnoreCase("block")) {
|
||||||
|
int type;
|
||||||
|
if (Material.matchMaterial(split[2]) != null)
|
||||||
|
type = Material.matchMaterial(split[2]).getId();
|
||||||
|
else
|
||||||
|
type = Integer.parseInt(split[2]);
|
||||||
|
AreaBlockSearch th = new AreaBlockSearch(conn, player, type, defaultDist);
|
||||||
|
new Thread(th).start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
player.sendMessage("<EFBFBD>cIncorrect usage.");
|
||||||
|
}
|
||||||
|
if (split[0].equalsIgnoreCase("/rollback"))
|
||||||
|
{
|
||||||
|
event.setCancelled(true);
|
||||||
|
if (!CheckPermission(event.getPlayer(),"logblock.rollback"))
|
||||||
|
{
|
||||||
|
event.getPlayer().sendMessage("<EFBFBD>cInsufficient permissions");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int minutes;
|
||||||
|
String name;
|
||||||
|
if (split.length < 3)
|
||||||
|
{
|
||||||
|
player.sendMessage("<EFBFBD>cUsage: /rollback [player] [time spec]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
name = split[1];
|
||||||
|
minutes = parseTimeSpec(event.getMessage().substring(event.getMessage().indexOf(' ', 11) + 1));
|
||||||
|
|
||||||
|
player.sendMessage("<EFBFBD>cRolling back " + name + " by " + minutes + " minutes.");
|
||||||
|
|
||||||
|
Connection conn;
|
||||||
|
try {
|
||||||
|
conn = getConnection();
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
log.log(Level.SEVERE, name + " SQL exception", ex);
|
||||||
|
player.sendMessage("<EFBFBD>cError, check server logs.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Rollback rb = new Rollback(conn, name, minutes);
|
||||||
|
player.sendMessage("<EFBFBD>cEdit count: " + rb.count());
|
||||||
|
new Thread(rb).start();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onPlayerItem(PlayerItemEvent event)
|
||||||
|
{
|
||||||
|
if (event.getMaterial() == Material.WATER_BUCKET)
|
||||||
|
queueBlock(event.getPlayer().getName(), event.getBlockClicked().getFace(event.getBlockFace()), 0, 9);
|
||||||
|
else if (event.getMaterial() == Material.LAVA_BUCKET)
|
||||||
|
queueBlock(event.getPlayer().getName(), event.getBlockClicked().getFace(event.getBlockFace()), 0, 11);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class LBLBlockListener extends BlockListener
|
||||||
|
{
|
||||||
|
public void onBlockRightClick(BlockRightClickEvent event)
|
||||||
|
{
|
||||||
|
if (event.getItemInHand().getTypeId() == toolID && CheckPermission(event.getPlayer(), "logblock.lookup"))
|
||||||
|
showBlockHistory(event.getPlayer(), event.getBlock());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onBlockPlace(BlockPlaceEvent event)
|
||||||
|
{
|
||||||
|
if (event.getItemInHand().getTypeId() == toolblockID && CheckPermission(event.getPlayer(), "logblock.lookup"))
|
||||||
|
{
|
||||||
|
showBlockHistory(event.getPlayer(), event.getBlockPlaced());
|
||||||
|
if (toolblockRemove)
|
||||||
|
event.setCancelled(true);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
queueBlock(event.getPlayer().getName(), event.getBlockPlaced(), event.getBlockReplacedState().getTypeId(), event.getBlockPlaced().getTypeId());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onBlockBreak(BlockBreakEvent event)
|
||||||
|
{
|
||||||
|
queueBlock(event.getPlayer().getName(), event.getBlock(), event.getBlock().getTypeId(), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Consumer implements Runnable
|
||||||
|
{
|
||||||
|
private boolean stop = false;
|
||||||
|
Consumer() { stop = false; }
|
||||||
|
public void stop() { stop = true; }
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
Connection conn = null;
|
||||||
|
BlockRow b;
|
||||||
|
|
||||||
|
while (!stop)
|
||||||
|
{
|
||||||
|
long start = System.currentTimeMillis()/1000L;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
if (bqueue.size() > 100)
|
||||||
|
log.info(name + " queue size " + bqueue.size());
|
||||||
|
|
||||||
|
try {
|
||||||
|
conn = getConnection();
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
while (count < 100 && start+delay > (System.currentTimeMillis()/1000L))
|
||||||
|
{
|
||||||
|
b = bqueue.poll(1L, TimeUnit.SECONDS);
|
||||||
|
|
||||||
|
if (b == null)
|
||||||
|
continue;
|
||||||
|
ps = conn.prepareStatement("INSERT INTO blocks (date, player, replaced, type, x, y, z) VALUES (now(),?,?,?,?,?,?)", Statement.RETURN_GENERATED_KEYS);
|
||||||
|
ps.setString(1, b.name);
|
||||||
|
ps.setInt(2, b.replaced);
|
||||||
|
ps.setInt(3, b.type);
|
||||||
|
ps.setInt(4, b.x);
|
||||||
|
ps.setInt(5, b.y);
|
||||||
|
ps.setInt(6, b.z);
|
||||||
|
ps.executeUpdate();
|
||||||
|
|
||||||
|
if (b.extra != null)
|
||||||
|
{
|
||||||
|
ResultSet keys = ps.getGeneratedKeys();
|
||||||
|
keys.next();
|
||||||
|
int key = keys.getInt(1);
|
||||||
|
|
||||||
|
ps = conn.prepareStatement("INSERT INTO extra (id, extra) values (?,?)");
|
||||||
|
ps.setInt(1, key);
|
||||||
|
ps.setString(2, b.extra);
|
||||||
|
ps.executeUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
conn.commit();
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
log.log(Level.SEVERE, name + " interrupted exception", ex);
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
log.log(Level.SEVERE, name + " SQL exception", ex);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (ps != null)
|
||||||
|
ps.close();
|
||||||
|
if (conn != null)
|
||||||
|
conn.close();
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
log.log(Level.SEVERE, name + " SQL exception on close", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class BlockRow
|
||||||
|
{
|
||||||
|
public String name;
|
||||||
|
public int replaced, type;
|
||||||
|
public int x, y, z;
|
||||||
|
public String extra;
|
||||||
|
|
||||||
|
BlockRow(String name, int replaced, int type, int x, int y, int z)
|
||||||
|
{
|
||||||
|
this.name = name;
|
||||||
|
this.replaced = replaced;
|
||||||
|
this.type = type;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
this.extra = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
//public void addExtra(String extra)
|
||||||
|
//{
|
||||||
|
// this.extra = extra;
|
||||||
|
//}
|
||||||
|
|
||||||
|
public String toString()
|
||||||
|
{
|
||||||
|
return("name: " + name + " before type: " + replaced + " type: " + type + " x: " + x + " y: " + y + " z: " + z);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Rollback implements Runnable
|
||||||
|
{
|
||||||
|
private LinkedBlockingQueue<Edit> edits = new LinkedBlockingQueue<Edit>();
|
||||||
|
|
||||||
|
Rollback(Connection conn, String name, int minutes)
|
||||||
|
{
|
||||||
|
String query = "select type, replaced, x, y, z from blocks where player = ? and date > date_sub(now(), interval ? minute) order by date desc";
|
||||||
|
PreparedStatement ps = null;
|
||||||
|
ResultSet rs = null;
|
||||||
|
edits.clear();
|
||||||
|
|
||||||
|
try {
|
||||||
|
conn.setAutoCommit(false);
|
||||||
|
ps = conn.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
|
||||||
|
ps.setString(1, name);
|
||||||
|
ps.setInt(2, minutes);
|
||||||
|
rs = ps.executeQuery();
|
||||||
|
|
||||||
|
while (rs.next())
|
||||||
|
{
|
||||||
|
Edit e = new Edit(rs.getInt("type"), rs.getInt("replaced"), rs.getInt("x"), rs.getInt("y"), rs.getInt("z"));
|
||||||
|
edits.offer(e);
|
||||||
|
}
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
log.log(Level.SEVERE, this.getClass().getName() + " SQL exception", ex);
|
||||||
|
} finally {
|
||||||
|
try {
|
||||||
|
if (rs != null)
|
||||||
|
rs.close();
|
||||||
|
if (ps != null)
|
||||||
|
ps.close();
|
||||||
|
if (conn != null)
|
||||||
|
conn.close();
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
log.log(Level.SEVERE, this.getClass().getName() + " SQL exception on close", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public int count()
|
||||||
|
{
|
||||||
|
return edits.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void run()
|
||||||
|
{
|
||||||
|
Edit e = edits.poll();
|
||||||
|
|
||||||
|
while (e != null)
|
||||||
|
{
|
||||||
|
e.perform();
|
||||||
|
e.log();
|
||||||
|
e = edits.poll();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class Edit
|
||||||
|
{
|
||||||
|
int type, replaced;
|
||||||
|
int x, y, z;
|
||||||
|
|
||||||
|
Edit(int type, int replaced, int x, int y, int z)
|
||||||
|
{
|
||||||
|
this.type = type;
|
||||||
|
this.replaced = replaced;
|
||||||
|
this.x = x;
|
||||||
|
this.y = y;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void perform()
|
||||||
|
{
|
||||||
|
Block block = getServer().getWorlds().get(0).getBlockAt(x, y, z);
|
||||||
|
if (block.getTypeId() == type)
|
||||||
|
{
|
||||||
|
if (block.setTypeId(replaced))
|
||||||
|
log.info("R (" + x + ", " + y + ", " + z + ") " + replaced + " " + type);
|
||||||
|
else
|
||||||
|
log.info("r (" + x + ", " + y + ", " + z + ") " + replaced + " " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void log()
|
||||||
|
{
|
||||||
|
int current = getServer().getWorlds().get(0).getBlockTypeIdAt(x, y, z);
|
||||||
|
if (current == type)
|
||||||
|
log.info("+ (" + x + ", " + y + ", " + z + ") " + replaced + " " + type);
|
||||||
|
else
|
||||||
|
log.info("- (" + x + ", " + y + ", " + z + ") " + replaced + " " + type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
49
PlayerAreaStats.java → src/com/bukkit/diddiz/LogBlock/PlayerAreaStats.java
Executable file → Normal file
49
PlayerAreaStats.java → src/com/bukkit/diddiz/LogBlock/PlayerAreaStats.java
Executable file → Normal file
@@ -1,8 +1,17 @@
|
|||||||
import java.util.HashSet;
|
package com.bukkit.diddiz.LogBlock;
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import java.util.logging.*;
|
import java.sql.Connection;
|
||||||
import java.sql.*;
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.bukkit.Material;
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public class PlayerAreaStats implements Runnable
|
public class PlayerAreaStats implements Runnable
|
||||||
{
|
{
|
||||||
@@ -32,30 +41,30 @@ public class PlayerAreaStats implements Runnable
|
|||||||
conn.setAutoCommit(false);
|
conn.setAutoCommit(false);
|
||||||
ps = conn.prepareStatement("SELECT type, count(type) as num from blocks where type > 0 and player = ? and y > 0 and x > ? and x < ? and z > ? and z < ? group by type order by count(replaced) desc limit 10", Statement.RETURN_GENERATED_KEYS);
|
ps = conn.prepareStatement("SELECT type, count(type) as num from blocks where type > 0 and player = ? and y > 0 and x > ? and x < ? and z > ? and z < ? group by type order by count(replaced) desc limit 10", Statement.RETURN_GENERATED_KEYS);
|
||||||
ps.setString(1, name);
|
ps.setString(1, name);
|
||||||
ps.setInt(2, (int)player.getX()-size);
|
ps.setInt(2, player.getLocation().getBlockX()-size);
|
||||||
ps.setInt(3, (int)player.getX()+size);
|
ps.setInt(3, player.getLocation().getBlockX()+size);
|
||||||
ps.setInt(4, (int)player.getZ()-size);
|
ps.setInt(4, player.getLocation().getBlockZ()-size);
|
||||||
ps.setInt(5, (int)player.getZ()+size);
|
ps.setInt(5, player.getLocation().getBlockZ()+size);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
while (rs.next())
|
while (rs.next())
|
||||||
{
|
{
|
||||||
types.add(etc.getDataSource().getItem(rs.getInt("type")));
|
types.add(Material.getMaterial(rs.getInt("type")).toString().toLowerCase().replace('_', ' '));
|
||||||
created.put(etc.getDataSource().getItem(rs.getInt("type")), rs.getInt("num"));
|
created.put(Material.getMaterial(rs.getInt("type")).toString().toLowerCase().replace('_', ' '), rs.getInt("num"));
|
||||||
}
|
}
|
||||||
rs.close();
|
rs.close();
|
||||||
ps.close();
|
ps.close();
|
||||||
|
|
||||||
ps = conn.prepareStatement("SELECT replaced, count(replaced) as num from blocks where replaced > 0 and player = ? and y > 0 and x > ? and x < ? and z > ? and z < ? group by replaced order by count(replaced) desc limit 10", Statement.RETURN_GENERATED_KEYS);
|
ps = conn.prepareStatement("SELECT replaced, count(replaced) as num from blocks where replaced > 0 and player = ? and y > 0 and x > ? and x < ? and z > ? and z < ? group by replaced order by count(replaced) desc limit 10", Statement.RETURN_GENERATED_KEYS);
|
||||||
ps.setString(1, name);
|
ps.setString(1, name);
|
||||||
ps.setInt(2, (int)player.getX()-size);
|
ps.setInt(2, player.getLocation().getBlockX()-size);
|
||||||
ps.setInt(3, (int)player.getX()+size);
|
ps.setInt(3, player.getLocation().getBlockX()+size);
|
||||||
ps.setInt(4, (int)player.getZ()-size);
|
ps.setInt(4, player.getLocation().getBlockZ()-size);
|
||||||
ps.setInt(5, (int)player.getZ()+size);
|
ps.setInt(5, player.getLocation().getBlockZ()+size);
|
||||||
rs = ps.executeQuery();
|
rs = ps.executeQuery();
|
||||||
while (rs.next())
|
while (rs.next())
|
||||||
{
|
{
|
||||||
types.add(etc.getDataSource().getItem(rs.getInt("replaced")));
|
types.add(Material.getMaterial(rs.getInt("replaced")).toString().toLowerCase().replace('_', ' '));
|
||||||
destroyed.put(etc.getDataSource().getItem(rs.getInt("replaced")), rs.getInt("num"));
|
destroyed.put(Material.getMaterial(rs.getInt("replaced")).toString().toLowerCase().replace('_', ' '), rs.getInt("num"));
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (SQLException ex) {
|
} catch (SQLException ex) {
|
||||||
@@ -73,14 +82,14 @@ public class PlayerAreaStats implements Runnable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
player.sendMessage(Colors.Blue + "Player " + name + " within " + size + " blocks of you: ");
|
player.sendMessage("§3Player " + name + " within " + size + " blocks of you: ");
|
||||||
if (types.size() == 0)
|
if (types.size() == 0)
|
||||||
{
|
{
|
||||||
player.sendMessage(Colors.Blue + "No results found.");
|
player.sendMessage("§3No results found.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
player.sendMessage(Colors.Gold + String.format("%-6s %-6s %s", "Creat", "Destr", "Block"));
|
player.sendMessage("§6" + String.format("%-6s %-6s %s", "Creat", "Destr", "Block"));
|
||||||
for (String t: types)
|
for (String t: types)
|
||||||
{
|
{
|
||||||
Integer c = created.get(t);
|
Integer c = created.get(t);
|
||||||
@@ -89,7 +98,7 @@ public class PlayerAreaStats implements Runnable
|
|||||||
c = 0;
|
c = 0;
|
||||||
if (d == null)
|
if (d == null)
|
||||||
d = 0;
|
d = 0;
|
||||||
player.sendMessage(Colors.Gold + String.format("%-6d %-6d %s", c, d, t));
|
player.sendMessage("§6" + String.format("%-6d %-6d %s", c, d, t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
24
PlayerWorldStats.java → src/com/bukkit/diddiz/LogBlock/PlayerWorldStats.java
Executable file → Normal file
24
PlayerWorldStats.java → src/com/bukkit/diddiz/LogBlock/PlayerWorldStats.java
Executable file → Normal file
@@ -1,8 +1,16 @@
|
|||||||
import java.util.HashSet;
|
package com.bukkit.diddiz.LogBlock;
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
import java.util.logging.*;
|
import java.sql.Connection;
|
||||||
import java.sql.*;
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
|
import java.sql.SQLException;
|
||||||
|
import java.sql.Statement;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import org.bukkit.entity.Player;
|
||||||
|
|
||||||
public class PlayerWorldStats implements Runnable
|
public class PlayerWorldStats implements Runnable
|
||||||
{
|
{
|
||||||
@@ -59,14 +67,14 @@ public class PlayerWorldStats implements Runnable
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
player.sendMessage(Colors.Blue + "Within entire world:");
|
player.sendMessage("§3Within entire world:");
|
||||||
if (players.size() == 0)
|
if (players.size() == 0)
|
||||||
{
|
{
|
||||||
player.sendMessage(Colors.Blue + "No results found.");
|
player.sendMessage("§3No results found.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
player.sendMessage(Colors.Gold + String.format("%-6s %-6s %s", "Creat", "Destr", "Player"));
|
player.sendMessage("§6" + String.format("%-6s %-6s %s", "Creat", "Destr", "Player"));
|
||||||
for (String p: players)
|
for (String p: players)
|
||||||
{
|
{
|
||||||
Integer c = created.get(p);
|
Integer c = created.get(p);
|
||||||
@@ -75,7 +83,7 @@ public class PlayerWorldStats implements Runnable
|
|||||||
c = 0;
|
c = 0;
|
||||||
if (d == null)
|
if (d == null)
|
||||||
d = 0;
|
d = 0;
|
||||||
player.sendMessage(Colors.Gold + String.format("%-6d %-6d %s", c, d, p));
|
player.sendMessage("§6" + String.format("%-6d %-6d %s", c, d, p));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
6
src/plugin.yml
Normal file
6
src/plugin.yml
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
name: LogBlock
|
||||||
|
version: 0.1
|
||||||
|
author: DiddiZ, bootswithdefer
|
||||||
|
website: http://www.diddiz.de/minecraft/
|
||||||
|
main: com.bukkit.diddiz.LogBlock.LogBlock
|
||||||
|
description: Logs blocks.
|
Reference in New Issue
Block a user