This commit is contained in:
Robin Kupper
2011-03-10 12:55:47 +01:00
parent 58471f6ca0
commit c1b0b9738e
16 changed files with 1370 additions and 771 deletions

38
.gitignore vendored
View File

@@ -1,34 +1,4 @@
# Compiled source #
###################
*.com
*.class
*.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
/.classpath
/.project
/.settings
/bin

Binary file not shown.

View File

@@ -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
View File

@@ -0,0 +1,3 @@
Manifest-Version: 1.0
Class-Path: ../mysql-connector-java-bin.jar

6
README
View File

@@ -1,4 +1,2 @@
See http://forum.hey0.net for information about these plugins.
To compile some packages are required (VersionCheck, JDBCPool)
that are available here: https://github.com/bootswithdefer/boots-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.

View File

@@ -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);
}
}
}

View File

@@ -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`)
);

View 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();
}
}
}

View 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;
}
}

View File

@@ -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;
}
}

View File

@@ -1,9 +1,18 @@
import java.util.HashSet;
import java.util.HashMap;
import java.text.SimpleDateFormat;
package com.bukkit.diddiz.LogBlock;
import java.util.logging.*;
import java.sql.*;
import java.sql.Connection;
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
{
@@ -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.setInt(1, type);
ps.setInt(2, type);
ps.setInt(3, (int)(location.y) - size);
ps.setInt(4, (int)(location.y) + size);
ps.setInt(5, (int)(location.x) - size);
ps.setInt(6, (int)(location.x) + size);
ps.setInt(7, (int)(location.z) - size);
ps.setInt(8, (int)(location.z) + size);
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(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())
{
@@ -51,12 +60,12 @@ public class AreaBlockSearch implements Runnable
String datestr = formatter.format(date);
String msg = datestr + " " + rs.getString("player") + " (" + rs.getInt("x") + ", " + rs.getInt("y") + ", " + rs.getInt("z") + ") ";
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)
msg = msg + "created " + etc.getDataSource().getItem(rs.getInt("type"));
msg = msg + "created " + Material.getMaterial(rs.getInt("type")).toString().toLowerCase().replace('_', ' ');
else
msg = msg + "replaced " + etc.getDataSource().getItem(rs.getInt("replaced")) + " with " + etc.getDataSource().getItem(rs.getInt("type"));
player.sendMessage(Colors.Gold + msg);
msg = msg + "replaced " + Material.getMaterial(rs.getInt("replaced")).toString().toLowerCase().replace('_', ' ') + " with " + Material.getMaterial(rs.getInt("type")).toString().toLowerCase().replace('_', ' ');
player.sendMessage("§6" + msg);
hist = true;
}
} catch (SQLException ex) {
@@ -74,6 +83,6 @@ public class AreaBlockSearch implements Runnable
}
}
if (!hist)
player.sendMessage(Colors.Blue + "None.");
player.sendMessage("§3None.");
}
}

View File

@@ -1,8 +1,16 @@
import java.util.HashSet;
import java.util.HashMap;
package com.bukkit.diddiz.LogBlock;
import java.util.logging.*;
import java.sql.*;
import java.sql.Connection;
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
{
@@ -29,12 +37,12 @@ public class AreaStats implements Runnable
try {
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.setInt(1, (int)player.getY()-size);
ps.setInt(2, (int)player.getY()+size);
ps.setInt(3, (int)player.getX()-size);
ps.setInt(4, (int)player.getX()+size);
ps.setInt(5, (int)player.getZ()-size);
ps.setInt(6, (int)player.getZ()+size);
ps.setInt(1, player.getLocation().getBlockY()-size);
ps.setInt(2, player.getLocation().getBlockY()+size);
ps.setInt(3, player.getLocation().getBlockX()-size);
ps.setInt(4, player.getLocation().getBlockX()+size);
ps.setInt(5, player.getLocation().getBlockZ()-size);
ps.setInt(6, player.getLocation().getBlockZ()+size);
rs = ps.executeQuery();
while (rs.next())
{
@@ -45,12 +53,12 @@ public class AreaStats implements Runnable
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.setInt(1, (int)player.getY()-size);
ps.setInt(2, (int)player.getY()+size);
ps.setInt(3, (int)player.getX()-size);
ps.setInt(4, (int)player.getX()+size);
ps.setInt(5, (int)player.getZ()-size);
ps.setInt(6, (int)player.getZ()+size);
ps.setInt(1, player.getLocation().getBlockY()-size);
ps.setInt(2, player.getLocation().getBlockY()+size);
ps.setInt(3, player.getLocation().getBlockX()-size);
ps.setInt(4, player.getLocation().getBlockX()+size);
ps.setInt(5, player.getLocation().getBlockZ()-size);
ps.setInt(6, player.getLocation().getBlockZ()+size);
rs = ps.executeQuery();
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)
{
player.sendMessage(Colors.Blue + "No results found.");
player.sendMessage("§3No results found.");
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)
{
Integer c = created.get(p);
@@ -89,7 +97,7 @@ public class AreaStats implements Runnable
c = 0;
if (d == null)
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));
}
}
}

View 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);
}
}
}
}

View File

@@ -1,8 +1,17 @@
import java.util.HashSet;
import java.util.HashMap;
package com.bukkit.diddiz.LogBlock;
import java.util.logging.*;
import java.sql.*;
import java.sql.Connection;
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
{
@@ -32,30 +41,30 @@ public class PlayerAreaStats implements Runnable
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.setString(1, name);
ps.setInt(2, (int)player.getX()-size);
ps.setInt(3, (int)player.getX()+size);
ps.setInt(4, (int)player.getZ()-size);
ps.setInt(5, (int)player.getZ()+size);
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);
rs = ps.executeQuery();
while (rs.next())
{
types.add(etc.getDataSource().getItem(rs.getInt("type")));
created.put(etc.getDataSource().getItem(rs.getInt("type")), rs.getInt("num"));
types.add(Material.getMaterial(rs.getInt("type")).toString().toLowerCase().replace('_', ' '));
created.put(Material.getMaterial(rs.getInt("type")).toString().toLowerCase().replace('_', ' '), rs.getInt("num"));
}
rs.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.setString(1, name);
ps.setInt(2, (int)player.getX()-size);
ps.setInt(3, (int)player.getX()+size);
ps.setInt(4, (int)player.getZ()-size);
ps.setInt(5, (int)player.getZ()+size);
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);
rs = ps.executeQuery();
while (rs.next())
{
types.add(etc.getDataSource().getItem(rs.getInt("replaced")));
destroyed.put(etc.getDataSource().getItem(rs.getInt("replaced")), rs.getInt("num"));
types.add(Material.getMaterial(rs.getInt("replaced")).toString().toLowerCase().replace('_', ' '));
destroyed.put(Material.getMaterial(rs.getInt("replaced")).toString().toLowerCase().replace('_', ' '), rs.getInt("num"));
}
} 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)
{
player.sendMessage(Colors.Blue + "No results found.");
player.sendMessage("§3No results found.");
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)
{
Integer c = created.get(t);
@@ -89,7 +98,7 @@ public class PlayerAreaStats implements Runnable
c = 0;
if (d == null)
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));
}
}
}

View File

@@ -1,8 +1,16 @@
import java.util.HashSet;
import java.util.HashMap;
package com.bukkit.diddiz.LogBlock;
import java.util.logging.*;
import java.sql.*;
import java.sql.Connection;
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
{
@@ -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)
{
player.sendMessage(Colors.Blue + "No results found.");
player.sendMessage("§3No results found.");
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)
{
Integer c = created.get(p);
@@ -75,7 +83,7 @@ public class PlayerWorldStats implements Runnable
c = 0;
if (d == null)
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
View 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.