2010-10-29 18:25:07 -07:00
import java.util.concurrent.TimeUnit ;
import java.util.concurrent.LinkedBlockingQueue ;
2010-11-11 13:16:38 -07:00
import java.text.SimpleDateFormat ;
2010-10-29 18:25:07 -07:00
2010-12-11 00:34:58 -07:00
import java.util.logging.* ;
2010-10-29 18:25:07 -07:00
import java.sql.* ;
2010-11-11 13:16:38 -07:00
import java.io.* ;
2010-10-29 18:25:07 -07:00
import net.minecraft.server.MinecraftServer ;
public class LogBlock extends Plugin
{
2010-11-11 13:16:38 -07:00
private static String name = "LogBlock" ;
2010-12-12 18:02:40 -07:00
private static int version = 13 ;
2010-11-11 13:16:38 -07:00
private boolean debug = false ;
2010-10-29 18:25:07 -07:00
private String dbDriver = "com.mysql.jdbc.Driver" ;
private String dbUrl = "" ;
private String dbUsername = "" ;
private String dbPassword = "" ;
2010-12-11 00:34:58 -07:00
private boolean usehModDb = false ;
2010-10-29 18:25:07 -07:00
private int delay = 10 ;
2010-12-12 18:02:40 -07:00
private int defaultDist = 20 ;
2010-12-11 00:34:58 -07:00
private int toolID = 270 ; // 270 is wood pick axe
private int toolblockID = 7 ; // 78 is adminium
private boolean toolblockRemove = true ;
2010-10-29 18:25:07 -07:00
private Consumer consumer = null ;
2010-12-03 08:31:00 -07:00
private Block lastface = null ;
2010-10-29 18:25:07 -07:00
private LinkedBlockingQueue < BlockRow > bqueue = new LinkedBlockingQueue < BlockRow > ();
static final Logger log = Logger . getLogger ( "Minecraft" );
2010-11-11 13:16:38 -07:00
static final Logger lblog = Logger . getLogger ( name );
2010-10-29 18:25:07 -07:00
public void enable ()
{
2010-12-13 15:19:38 -07:00
new VersionCheck ( name , version );
2010-10-29 18:25:07 -07:00
PropertiesFile properties = new PropertiesFile ( "logblock.properties" );
try {
2010-11-11 13:16:38 -07:00
debug = properties . getBoolean ( "debug" , false );
2010-12-11 00:34:58 -07:00
usehModDb = properties . getBoolean ( "use-hmod-db" , false );
2010-10-29 18:25:07 -07:00
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" );
2010-12-11 00:34:58 -07:00
delay = properties . getInt ( "delay" , 6 );
2010-10-29 18:25:07 -07:00
toolID = properties . getInt ( "tool-id" , 270 );
2010-12-11 00:34:58 -07:00
toolblockID = properties . getInt ( "tool-block-id" , 7 );
toolblockRemove = properties . getBoolean ( "tool-block-remove" , true );
2010-12-12 18:02:40 -07:00
defaultDist = properties . getInt ( "default-distance" , 20 );
2010-10-29 18:25:07 -07:00
} catch ( Exception ex ) {
2010-12-13 15:19:38 -07:00
log . log ( Level . SEVERE , name + ": exception while reading from logblock.properties" , ex );
return ;
2010-11-06 21:51:47 -07:00
}
2010-10-29 18:25:07 -07:00
try {
2010-12-11 00:34:58 -07:00
if ( ! usehModDb )
new JDCConnectionDriver ( dbDriver , dbUrl , dbUsername , dbPassword );
2010-10-29 18:25:07 -07:00
} catch ( Exception ex ) {
2010-12-13 15:19:38 -07:00
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." );
2010-10-29 18:25:07 -07:00
return ;
}
consumer = new Consumer ();
new Thread ( consumer ). start ();
2010-12-12 18:02:40 -07:00
etc . getInstance (). addCommand ( "/lb" , " - LogBlock display command." );
etc . getInstance (). addCommand ( "/rollback" , " - LogBlock Rollback command." );
2010-10-29 18:25:07 -07:00
log . info ( name + " v" + version + " Plugin Enabled." );
}
public void disable ()
{
2010-11-12 12:15:56 -07:00
if ( consumer != null )
consumer . stop ();
2010-10-29 18:25:07 -07:00
consumer = null ;
2010-12-12 18:02:40 -07:00
etc . getInstance (). removeCommand ( "/lb" );
etc . getInstance (). removeCommand ( "/rollback" );
2010-10-29 18:25:07 -07:00
log . info ( name + " v" + version + " Plugin Disabled." );
}
public void initialize ()
{
2010-11-11 13:16:38 -07:00
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" );
}
2010-10-29 18:25:07 -07:00
LBListener listener = new LBListener ();
etc . getLoader (). addListener ( PluginLoader . Hook . COMMAND , listener , this , PluginListener . Priority . LOW );
2010-12-03 08:31:00 -07:00
etc . getLoader (). addListener ( PluginLoader . Hook . BLOCK_RIGHTCLICKED , listener , this , PluginListener . Priority . LOW );
etc . getLoader (). addListener ( PluginLoader . Hook . BLOCK_PLACE , listener , this , PluginListener . Priority . LOW );
2010-11-11 13:16:38 -07:00
etc . getLoader (). addListener ( PluginLoader . Hook . BLOCK_BROKEN , listener , this , PluginListener . Priority . LOW );
2010-12-13 15:19:38 -07:00
etc . getLoader (). addListener ( PluginLoader . Hook . COMPLEX_BLOCK_CHANGE , listener , this , PluginListener . Priority . LOW );
2010-10-29 18:25:07 -07:00
}
private Connection getConnection () throws SQLException
{
2010-12-11 00:34:58 -07:00
if ( usehModDb )
return etc . getSQLConnection ();
2010-10-29 18:25:07 -07:00
return DriverManager . getConnection ( "jdbc:jdc:jdcpool" );
}
2010-12-13 15:19:38 -07:00
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 ;
}
2010-10-29 18:25:07 -07:00
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 ;
2010-11-11 13:16:38 -07:00
Timestamp date ;
SimpleDateFormat formatter = new SimpleDateFormat ( "MM-dd hh:mm:ss" );
2010-10-29 18:25:07 -07:00
try {
conn = getConnection ();
conn . setAutoCommit ( false );
2010-12-13 15:19:38 -07:00
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 );
2010-11-13 14:07:17 -07:00
ps . setInt ( 1 , b . getY ());
ps . setInt ( 2 , b . getX ());
2010-10-29 18:25:07 -07:00
ps . setInt ( 3 , b . getZ ());
rs = ps . executeQuery ();
while ( rs . next ())
{
2010-11-11 13:16:38 -07:00
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 )
2010-12-13 15:19:38 -07:00
{
if ( rs . getInt ( "type" ) == 323 ) // sign
msg = msg + "created " + rs . getString ( "extra" );
else
msg = msg + "created " + etc . getDataSource (). getItem ( rs . getInt ( "type" ));
}
2010-11-11 13:16:38 -07:00
else
msg = msg + "replaced " + etc . getDataSource (). getItem ( rs . getInt ( "replaced" )) + " with " + etc . getDataSource (). getItem ( rs . getInt ( "type" ));
2010-11-02 16:26:47 -07:00
player . sendMessage ( Colors . Gold + msg );
2010-10-29 18:25:07 -07:00
hist = true ;
}
} catch ( SQLException ex ) {
log . log ( Level . SEVERE , name + " SQL exception" , ex );
} finally {
try {
2010-11-12 12:15:56 -07:00
if ( rs != null )
rs . close ();
if ( ps != null )
ps . close ();
2010-12-11 00:34:58 -07:00
if ( conn != null )
conn . close ();
2010-10-29 18:25:07 -07:00
} catch ( SQLException ex ) {
log . log ( Level . SEVERE , name + " SQL exception on close" , ex );
}
}
if ( ! hist )
player . sendMessage ( Colors . Blue + "None." );
}
2010-11-02 16:26:47 -07:00
2010-11-11 13:16:38 -07:00
private void queueBlock ( Player player , Block before , Block after )
{
2010-12-03 08:31:00 -07:00
Block b = null ;
int typeA = 0 ;
int typeB = 0 ;
if ( after != null )
{
typeA = after . getType ();
b = after ;
2010-11-11 13:16:38 -07:00
}
2010-12-03 08:31:00 -07:00
if ( before != null )
{
typeB = before . getType ();
b = before ;
}
if ( b == null || typeA < 0 || typeB < 0 )
2010-11-11 13:16:38 -07:00
return ;
2010-12-03 08:31:00 -07:00
BlockRow row = new BlockRow ( player . getName (), typeB , typeA , b . getX (), b . getY (), b . getZ ());
2010-11-11 13:16:38 -07:00
boolean result = bqueue . offer ( row );
if ( debug )
lblog . info ( row . toString ());
if ( ! result )
log . info ( name + " failed to queue block for " + player . getName ());
}
2010-12-12 18:02:40 -07:00
2010-12-13 15:19:38 -07:00
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 ());
}
2010-12-12 18:02:40 -07:00
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 ;
}
2010-11-11 13:16:38 -07:00
2010-10-29 18:25:07 -07:00
public class LBListener extends PluginListener // start
{
public boolean onCommand ( Player player , String [] split )
{
if ( ! player . canUseCommand ( split [ 0 ] ))
return false ;
2010-12-11 00:34:58 -07:00
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 ;
}
2010-11-02 16:26:47 -07:00
if ( split . length == 1 ) {
2010-12-11 00:34:58 -07:00
AreaStats th = new AreaStats ( conn , player , defaultDist );
2010-11-09 11:04:11 -07:00
new Thread ( th ). start ();
2010-11-02 16:26:47 -07:00
return true ;
}
2010-12-11 00:34:58 -07:00
2010-11-02 16:26:47 -07:00
if ( split . length == 2 ) {
2010-11-09 11:04:11 -07:00
if ( split [ 1 ] . equalsIgnoreCase ( "world" )) {
2010-12-11 00:34:58 -07:00
PlayerWorldStats th = new PlayerWorldStats ( conn , player );
2010-11-09 11:04:11 -07:00
new Thread ( th ). start ();
2010-12-11 00:34:58 -07:00
return true ;
}
player . sendMessage ( Colors . Rose + "Incorrect usage." );
2010-11-02 16:26:47 -07:00
return true ;
}
2010-12-11 00:34:58 -07:00
2010-11-09 11:04:11 -07:00
if ( split [ 1 ] . equalsIgnoreCase ( "player" )) {
2010-12-11 00:34:58 -07:00
PlayerAreaStats th = new PlayerAreaStats ( conn , player , split [ 2 ] , defaultDist );
2010-11-09 11:04:11 -07:00
new Thread ( th ). start ();
2010-12-11 00:34:58 -07:00
return true ;
2010-11-09 11:04:11 -07:00
}
2010-12-11 00:34:58 -07:00
if ( split [ 1 ] . equalsIgnoreCase ( "area" )) {
AreaStats th = new AreaStats ( conn , player , Integer . parseInt ( split [ 2 ] ));
2010-11-09 11:04:11 -07:00
new Thread ( th ). start ();
2010-12-11 00:34:58 -07:00
return true ;
2010-11-09 11:04:11 -07:00
}
2010-12-11 00:34:58 -07:00
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." );
2010-10-29 18:25:07 -07:00
return true ;
}
2010-12-12 18:02:40 -07:00
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 ;
}
2010-10-29 18:25:07 -07:00
return false ;
}
2010-12-03 08:31:00 -07:00
public void onBlockRightClicked ( Player player , Block blockClicked , Item item )
2010-10-29 18:25:07 -07:00
{
2010-12-03 08:31:00 -07:00
if ( item . getItemId () == toolID && player . canUseCommand ( "/blockhistory" ))
2010-12-11 00:34:58 -07:00
{
2010-10-29 18:25:07 -07:00
showBlockHistory ( player , blockClicked );
2010-12-11 00:34:58 -07:00
return ;
}
2010-12-03 08:31:00 -07:00
lastface = blockClicked . getFace ( blockClicked . getFaceClicked ());
2010-12-13 15:19:38 -07:00
if ( debug )
lblog . info ( "onBlockRightClicked: clicked " + blockClicked . getType () + " item " + item . getItemId () + " face " + blockClicked . getFace ( blockClicked . getFaceClicked ()). getType ());
2010-12-03 08:31:00 -07:00
}
public boolean onBlockPlace ( Player player , Block blockPlaced , Block blockClicked , Item itemInHand )
{
2010-12-11 00:34:58 -07:00
if ( itemInHand . getItemId () == toolblockID && player . canUseCommand ( "/blockhistory" ))
{
showBlockHistory ( player , blockPlaced );
if ( toolblockRemove )
return true ;
return false ;
}
2010-12-13 15:19:38 -07:00
if ( debug )
lblog . info ( "onBlockPlace: placed " + blockPlaced . getType () + " clicked " + blockClicked . getType () + " item " + itemInHand . getItemId ());
2010-12-03 08:31:00 -07:00
queueBlock ( player , lastface , blockPlaced );
2010-10-29 18:25:07 -07:00
return false ;
}
2010-11-11 13:16:38 -07:00
public boolean onBlockBreak ( Player player , Block block )
2010-10-29 18:25:07 -07:00
{
2010-11-11 13:16:38 -07:00
queueBlock ( player , block , null );
2010-10-29 18:25:07 -07:00
return false ;
}
2010-12-13 15:19:38 -07:00
public boolean onComplexBlockChange ( Player player , ComplexBlock cb )
{
if ( cb instanceof Sign )
{
Sign sign = ( Sign ) cb ;
queueSign ( player , sign );
}
return false ;
}
2010-10-29 18:25:07 -07:00
} // 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 )
{
2010-12-04 17:12:43 -07:00
long start = System . currentTimeMillis () / 1000L ;
2010-10-29 18:25:07 -07:00
int count = 0 ;
if ( bqueue . size () > 100 )
log . info ( name + " queue size " + bqueue . size ());
2010-12-04 17:12:43 -07:00
// if (debug)
// lblog.info("Running DB thread at " + start);
2010-10-29 18:25:07 -07:00
try {
conn = getConnection ();
conn . setAutoCommit ( false );
2010-11-09 11:04:11 -07:00
ps = conn . prepareStatement ( "INSERT INTO blocks (date, player, replaced, type, x, y, z) VALUES (now(),?,?,?,?,?,?)" , Statement . RETURN_GENERATED_KEYS );
2010-10-29 18:25:07 -07:00
2010-12-04 17:12:43 -07:00
while ( count < 100 && start + delay > ( System . currentTimeMillis () / 1000L ))
2010-10-29 18:25:07 -07:00
{
2010-12-04 17:12:43 -07:00
// if (debug)
// lblog.info("Loop DB thread at " + (System.currentTimeMillis()/1000L));
2010-10-29 18:25:07 -07:00
b = bqueue . poll ( 1L , TimeUnit . SECONDS );
if ( b == null )
continue ;
//b.log();
ps . setString ( 1 , b . name );
2010-11-09 11:04:11 -07:00
ps . setInt ( 2 , b . replaced );
2010-10-29 18:25:07 -07:00
ps . setInt ( 3 , b . type );
ps . setInt ( 4 , b . x );
ps . setInt ( 5 , b . y );
ps . setInt ( 6 , b . z );
ps . executeUpdate ();
2010-12-13 15:19:38 -07:00
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 ();
}
2010-10-29 18:25:07 -07:00
count ++ ;
}
2010-12-04 17:12:43 -07:00
if ( debug && count > 0 )
lblog . info ( "Commiting " + count + " inserts." );
2010-10-29 18:25:07 -07:00
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 {
2010-12-11 00:34:58 -07:00
if ( ps != null )
ps . close ();
if ( conn != null )
conn . close ();
2010-10-29 18:25:07 -07:00
} catch ( SQLException ex ) {
log . log ( Level . SEVERE , name + " SQL exception on close" , ex );
}
}
}
}
} // end LBDB
private class BlockRow // start
{
public String name ;
2010-11-09 11:04:11 -07:00
public int replaced , type ;
2010-10-29 18:25:07 -07:00
public int x , y , z ;
2010-12-13 15:19:38 -07:00
public String extra ;
2010-10-29 18:25:07 -07:00
2010-11-09 11:04:11 -07:00
BlockRow ( String name , int replaced , int type , int x , int y , int z )
2010-10-29 18:25:07 -07:00
{
this . name = name ;
2010-11-09 11:04:11 -07:00
this . replaced = replaced ;
2010-10-29 18:25:07 -07:00
this . type = type ;
this . x = x ;
this . y = y ;
this . z = z ;
2010-12-13 15:19:38 -07:00
this . extra = null ;
}
public void addExtra ( String extra )
{
this . extra = extra ;
2010-10-29 18:25:07 -07:00
}
2010-11-11 13:16:38 -07:00
public String toString ()
2010-10-29 18:25:07 -07:00
{
2010-11-11 13:16:38 -07:00
return ( "name: " + name + " before type: " + replaced + " type: " + type + " x: " + x + " y: " + y + " z: " + z );
2010-10-29 18:25:07 -07:00
}
2010-11-09 11:04:11 -07:00
} // end BlockRow
2010-11-11 13:16:38 -07:00
private class Result // start
2010-11-09 11:04:11 -07:00
{
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 ));
}
2010-11-11 13:16:38 -07:00
} // end Result
private class LogFormatter extends Formatter //start
{
public String format ( LogRecord rec )
{
return formatMessage ( rec ) + "\n" ;
}
} // end LogFormatter
2010-10-29 18:25:07 -07:00
} // end LogBlock