diff --git a/.gitignore b/.gitignore index 3677c8b..ea7eba2 100644 --- a/.gitignore +++ b/.gitignore @@ -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 \ No newline at end of file diff --git a/LogBlock.jar b/LogBlock.jar deleted file mode 100755 index 3305b71..0000000 Binary files a/LogBlock.jar and /dev/null differ diff --git a/LogBlock.java b/LogBlock.java deleted file mode 100755 index 066cca5..0000000 --- a/LogBlock.java +++ /dev/null @@ -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 bqueue = new LinkedBlockingQueue(); - - 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 diff --git a/MANIFEST.MF b/MANIFEST.MF new file mode 100644 index 0000000..d8ea047 --- /dev/null +++ b/MANIFEST.MF @@ -0,0 +1,3 @@ +Manifest-Version: 1.0 +Class-Path: ../mysql-connector-java-bin.jar + diff --git a/README b/README index e320bb4..ec9042c 100644 --- a/README +++ b/README @@ -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. \ No newline at end of file diff --git a/Rollback.java b/Rollback.java deleted file mode 100755 index 2431f7a..0000000 --- a/Rollback.java +++ /dev/null @@ -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 edits = new LinkedBlockingQueue(); - - 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); - } - } -} \ No newline at end of file diff --git a/schema.sql b/schema.sql deleted file mode 100644 index 7562e2e..0000000 --- a/schema.sql +++ /dev/null @@ -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`) -); diff --git a/src/com/bukkit/bootswithdefer/JDCBPool/ConnectionService.java b/src/com/bukkit/bootswithdefer/JDCBPool/ConnectionService.java new file mode 100644 index 0000000..3466cce --- /dev/null +++ b/src/com/bukkit/bootswithdefer/JDCBPool/ConnectionService.java @@ -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; + +/** + * Purpose:Realizes a connection pool for all JDBC connections.
+ * Description:http://java.sun.com/developer/onlineTraining/Programming/JDCBook/ + * conpool.html
+ * Copyright:Licensed under the Apache License, Version 2.0. + * http://www.apache.org/licenses/LICENSE-2.0
+ * Company:SIMPL
+ * + * @author schneimi + * @version $Id$
+ * @link http://code.google.com/p/simpl09/ + */ +public class ConnectionService { + private Vector 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(poolsize); + reaper = new ConnectionReaper(this); + reaper.start(); + } + + public synchronized void reapConnections() { + long stale = System.currentTimeMillis() - timeout; + Enumeration 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 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(); + } + } +} diff --git a/src/com/bukkit/bootswithdefer/JDCBPool/JDCConnection.java b/src/com/bukkit/bootswithdefer/JDCBPool/JDCConnection.java new file mode 100644 index 0000000..843d44c --- /dev/null +++ b/src/com/bukkit/bootswithdefer/JDCBPool/JDCConnection.java @@ -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; + +/** + * Purpose:Wrapper for JDBCConnection.
+ * Description:http://java.sun.com/developer/onlineTraining/Programming/JDCBook/ + * conpool.html
+ * Copyright:Licensed under the Apache License, Version 2.0. + * http://www.apache.org/licenses/LICENSE-2.0
+ * Company:SIMPL
+ * + * @author schneimi + * @version $Id$
+ * @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> 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> 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 unwrap(Class iface) throws SQLException { + // TODO Auto-generated method stub + return null; + } +} diff --git a/src/com/bukkit/bootswithdefer/JDCBPool/JDCConnectionDriver.java b/src/com/bukkit/bootswithdefer/JDCBPool/JDCConnectionDriver.java new file mode 100644 index 0000000..054908a --- /dev/null +++ b/src/com/bukkit/bootswithdefer/JDCBPool/JDCConnectionDriver.java @@ -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; + +/** + * Purpose:Wrapper for JDBCConnectionDriver.
+ * Description:http://java.sun.com/developer/onlineTraining/Programming/JDCBook/ + * conpool.html
+ * Copyright:Licensed under the Apache License, Version 2.0. + * http://www.apache.org/licenses/LICENSE-2.0
+ * Company: SIMPL
+ * + * @author schneimi + * @version $Id: JDCConnectionDriver.java 1224 2010-04-28 14:17:34Z + * michael.schneidt@arcor.de $
+ * @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; + } +} diff --git a/AreaBlockSearch.java b/src/com/bukkit/diddiz/LogBlock/AreaBlockSearch.java old mode 100755 new mode 100644 similarity index 54% rename from AreaBlockSearch.java rename to src/com/bukkit/diddiz/LogBlock/AreaBlockSearch.java index 90a8812..0326ab8 --- a/AreaBlockSearch.java +++ b/src/com/bukkit/diddiz/LogBlock/AreaBlockSearch.java @@ -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."); } } diff --git a/AreaStats.java b/src/com/bukkit/diddiz/LogBlock/AreaStats.java old mode 100755 new mode 100644 similarity index 61% rename from AreaStats.java rename to src/com/bukkit/diddiz/LogBlock/AreaStats.java index 5192f12..6d9c3aa --- a/AreaStats.java +++ b/src/com/bukkit/diddiz/LogBlock/AreaStats.java @@ -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)); } } } diff --git a/src/com/bukkit/diddiz/LogBlock/LogBlock.java b/src/com/bukkit/diddiz/LogBlock/LogBlock.java new file mode 100644 index 0000000..8f72eb3 --- /dev/null +++ b/src/com/bukkit/diddiz/LogBlock/LogBlock.java @@ -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 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 bqueue = new LinkedBlockingQueue(); + + 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("§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("§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("§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("§cInsufficient permissions"); + return; + } + Connection conn; + try { + conn = getConnection(); + } + catch (SQLException ex) { + log.log(Level.SEVERE, name + " SQL exception", ex); + player.sendMessage("§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("§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("§cIncorrect usage."); + } + if (split[0].equalsIgnoreCase("/rollback")) + { + event.setCancelled(true); + if (!CheckPermission(event.getPlayer(),"logblock.rollback")) + { + event.getPlayer().sendMessage("§cInsufficient permissions"); + return; + } + int minutes; + String name; + if (split.length < 3) + { + player.sendMessage("§cUsage: /rollback [player] [time spec]"); + return; + } + name = split[1]; + minutes = parseTimeSpec(event.getMessage().substring(event.getMessage().indexOf(' ', 11) + 1)); + + player.sendMessage("§cRolling back " + name + " by " + minutes + " minutes."); + + Connection conn; + try { + conn = getConnection(); + } catch (SQLException ex) { + log.log(Level.SEVERE, name + " SQL exception", ex); + player.sendMessage("§cError, check server logs."); + return; + } + Rollback rb = new Rollback(conn, name, minutes); + player.sendMessage("§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 edits = new LinkedBlockingQueue(); + + 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); + } + } + } +} diff --git a/PlayerAreaStats.java b/src/com/bukkit/diddiz/LogBlock/PlayerAreaStats.java old mode 100755 new mode 100644 similarity index 55% rename from PlayerAreaStats.java rename to src/com/bukkit/diddiz/LogBlock/PlayerAreaStats.java index 1ee1435..ff4b5df --- a/PlayerAreaStats.java +++ b/src/com/bukkit/diddiz/LogBlock/PlayerAreaStats.java @@ -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)); } } } diff --git a/PlayerWorldStats.java b/src/com/bukkit/diddiz/LogBlock/PlayerWorldStats.java old mode 100755 new mode 100644 similarity index 75% rename from PlayerWorldStats.java rename to src/com/bukkit/diddiz/LogBlock/PlayerWorldStats.java index a30a817..716872a --- a/PlayerWorldStats.java +++ b/src/com/bukkit/diddiz/LogBlock/PlayerWorldStats.java @@ -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)); } } } diff --git a/src/plugin.yml b/src/plugin.yml new file mode 100644 index 0000000..9e2716d --- /dev/null +++ b/src/plugin.yml @@ -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. \ No newline at end of file