From a1061ff2e4e73c4b5c5ba27d7cd1a3922173cc94 Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Tue, 26 Mar 2013 03:31:43 +0500 Subject: [PATCH 01/50] Added ability to disable id sanity check --- src/main/java/de/diddiz/LogBlock/Consumer.java | 2 +- src/main/java/de/diddiz/LogBlock/config/Config.java | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 90632f6..8f22a29 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -391,7 +391,7 @@ public class Consumer extends TimerTask ca = event.getChestAccess(); } // Do this last so LogBlock still has final say in what is being added - if (playerName == null || loc == null || typeBefore < 0 || typeAfter < 0 || typeBefore > 255 || typeAfter > 255 || hiddenPlayers.contains(playerName.toLowerCase()) || !isLogged(loc.getWorld()) || typeBefore != typeAfter && hiddenBlocks.contains(typeBefore) && hiddenBlocks.contains(typeAfter)) return; + if (playerName == null || loc == null || typeBefore < 0 || typeAfter < 0 || (Config.safetyIdCheck && (typeBefore > 255 || typeAfter > 255)) || hiddenPlayers.contains(playerName.toLowerCase()) || !isLogged(loc.getWorld()) || typeBefore != typeAfter && hiddenBlocks.contains(typeBefore) && hiddenBlocks.contains(typeAfter)) return; queue.add(new BlockRow(loc, playerName.replaceAll("[^a-zA-Z0-9_]", ""), typeBefore, typeAfter, data, signtext, ca)); } diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index e7898c2..9d05e46 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -45,6 +45,7 @@ public class Config public static Set hiddenPlayers; public static Set ignoredChat; public static SimpleDateFormat formatter; + public static boolean safetyIdCheck; public static enum LogKillsLevel { @@ -123,6 +124,7 @@ public class Config def.put("tools.toolblock.params", "area 0 all sum none limit 15 desc silent"); def.put("tools.toolblock.mode", "LOOKUP"); def.put("tools.toolblock.permissionDefault", "OP"); + def.put("safety.id.check", true); for (final Entry e : def.entrySet()) if (!config.contains(e.getKey())) config.set(e.getKey(), e.getValue()); @@ -175,6 +177,7 @@ public class Config askClearLogs = config.getBoolean("questioner.askClearLogs", true); askClearLogAfterRollback = config.getBoolean("questioner.askClearLogAfterRollback", true); askRollbackAfterBan = config.getBoolean("questioner.askRollbackAfterBan", false); + safetyIdCheck = config.getBoolean("safety.id.check", true); banPermission = config.getString("questioner.banPermission"); final List tools = new ArrayList(); final ConfigurationSection toolsSec = config.getConfigurationSection("tools"); From 602b1192d196291581f173c9a1dffe1180961cda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Teichmann?= Date: Sat, 16 Mar 2013 16:59:50 +0100 Subject: [PATCH 02/50] Fix SMALLINT only allowing 65535 players to log We just ran into the problem where new users didn't make any edits and after some digging I just found out why: The playerid in the kb-players table was a SMALLINT. Changing that to an INT should work for some more years now ;-) --- src/main/java/de/diddiz/LogBlock/Updater.java | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 84c6759..01fe971 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -197,6 +197,26 @@ class Updater } config.set("version", "1.52"); } + this.logblock.getServer().getScheduler().runTaskAsynchronously(this.logblock, new Thread() { + + @Override + public void run() { + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + ResultSet rs = st.executeQuery("SELECT auto_increment FROM information_schema.columns AS col join information_schema.tables AS tab ON (col.table_schema=tab.table_schema AND col.table_name=tab.table_name) WHERE col.table_name = 'lb-players' AND col.column_name = 'playerid' AND col.data_type = 'smallint' AND col.table_schema = DATABASE() AND auto_increment > 65000;"); + if (rs.next()) { + logblock.getLogger().warning("Your server reached 65000 players. You should soon update your database table schema - see FAQ: https://github.com/LogBlock/LogBlock/wiki/FAQ#logblock-your-server-reached-65000-players-"); + } + st.close(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + } + } + + }); logblock.saveConfig(); return true; } @@ -208,15 +228,15 @@ class Updater final Statement state = conn.createStatement(); final DatabaseMetaData dbm = conn.getMetaData(); conn.setAutoCommit(true); - createTable(dbm, state, "lb-players", "(playerid SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, playername varchar(32) NOT NULL, firstlogin DATETIME NOT NULL, lastlogin DATETIME NOT NULL, onlinetime INT UNSIGNED NOT NULL, ip varchar(255) NOT NULL, PRIMARY KEY (playerid), UNIQUE (playername))"); + createTable(dbm, state, "lb-players", "(playerid INT UNSIGNED NOT NULL AUTO_INCREMENT, playername varchar(32) NOT NULL, firstlogin DATETIME NOT NULL, lastlogin DATETIME NOT NULL, onlinetime INT UNSIGNED NOT NULL, ip varchar(255) NOT NULL, PRIMARY KEY (playerid), UNIQUE (playername))"); if (isLogging(Logging.CHAT)) - createTable(dbm, state, "lb-chat", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid SMALLINT UNSIGNED NOT NULL, message VARCHAR(255) NOT NULL, PRIMARY KEY (id), KEY playerid (playerid), FULLTEXT message (message)) ENGINE=MyISAM"); + createTable(dbm, state, "lb-chat", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, message VARCHAR(255) NOT NULL, PRIMARY KEY (id), KEY playerid (playerid), FULLTEXT message (message)) ENGINE=MyISAM"); for (final WorldConfig wcfg : getLoggedWorlds()) { - createTable(dbm, state, wcfg.table, "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid SMALLINT UNSIGNED NOT NULL, replaced TINYINT UNSIGNED NOT NULL, type TINYINT UNSIGNED NOT NULL, data TINYINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))"); + createTable(dbm, state, wcfg.table, "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced TINYINT UNSIGNED NOT NULL, type TINYINT UNSIGNED NOT NULL, data TINYINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))"); createTable(dbm, state, wcfg.table + "-sign", "(id INT UNSIGNED NOT NULL, signtext VARCHAR(255) NOT NULL, PRIMARY KEY (id))"); createTable(dbm, state, wcfg.table + "-chest", "(id INT UNSIGNED NOT NULL, itemtype SMALLINT UNSIGNED NOT NULL, itemamount SMALLINT NOT NULL, itemdata TINYINT UNSIGNED NOT NULL, PRIMARY KEY (id))"); if (wcfg.isLogging(Logging.KILL)) - createTable(dbm, state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer SMALLINT UNSIGNED, victim SMALLINT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x SMALLINT NOT NULL, y TINYINT UNSIGNED NOT NULL, z SMALLINT NOT NULL, PRIMARY KEY (id))"); + createTable(dbm, state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x SMALLINT NOT NULL, y TINYINT UNSIGNED NOT NULL, z SMALLINT NOT NULL, PRIMARY KEY (id))"); } state.close(); conn.close(); From ac82d8848bc9bed58700da550ed7f4a5d9ea6498 Mon Sep 17 00:00:00 2001 From: frymaster Date: Sat, 8 Jun 2013 21:10:43 +0100 Subject: [PATCH 03/50] Use alternate method of logging deaths. Fixes #350 --- .../diddiz/LogBlock/listeners/KillLogging.java | 17 +++++------------ 1 file changed, 5 insertions(+), 12 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java index 0f34325..c4f8313 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java @@ -2,8 +2,6 @@ package de.diddiz.LogBlock.listeners; import static de.diddiz.LogBlock.config.Config.isLogging; import static de.diddiz.LogBlock.config.Config.logKillsLevel; -import java.util.HashMap; -import java.util.Map; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Monster; @@ -12,35 +10,30 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; +import org.bukkit.event.entity.EntityDeathEvent; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.Config.LogKillsLevel; public class KillLogging extends LoggingListener { - private final Map lastAttackedEntity = new HashMap(); - private final Map lastAttackTime = new HashMap(); public KillLogging(LogBlock lb) { super(lb); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onEntityDamage(EntityDamageEvent event) { - if (isLogging(event.getEntity().getWorld(), Logging.KILL) && event instanceof EntityDamageByEntityEvent && event.getEntity() instanceof LivingEntity) { + public void onEntityDeath(EntityDeathEvent deathEvent) { + EntityDamageEvent event = deathEvent.getEntity().getLastDamageCause(); + // For a death event, there should always be a damage event and it should not be cancelled. Check anyway. + if (event!= null && event.isCancelled() == false && isLogging(event.getEntity().getWorld(), Logging.KILL) && event instanceof EntityDamageByEntityEvent && event.getEntity() instanceof LivingEntity) { final LivingEntity victim = (LivingEntity)event.getEntity(); final Entity killer = ((EntityDamageByEntityEvent)event).getDamager(); - if (victim.getHealth() - event.getDamage() > 0 || victim.getHealth() <= 0) - return; if (logKillsLevel == LogKillsLevel.PLAYERS && !(victim instanceof Player && killer instanceof Player)) return; else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster) && killer instanceof Player || killer instanceof Monster)) return; - if (lastAttackedEntity.containsKey(killer.getEntityId()) && lastAttackedEntity.get(killer.getEntityId()) == victim.getEntityId() && System.currentTimeMillis() - lastAttackTime.get(killer.getEntityId()) < 5000) - return; consumer.queueKill(killer, victim); - lastAttackedEntity.put(killer.getEntityId(), victim.getEntityId()); - lastAttackTime.put(killer.getEntityId(), System.currentTimeMillis()); } } } From b7398bfde141488e244cab1b3cb2a3df6038d248 Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Thu, 8 Aug 2013 19:10:09 +0500 Subject: [PATCH 04/50] Re-organize task to be run onEnable, should fix #468 --- .../java/de/diddiz/LogBlock/LogBlock.java | 29 ++++++-- src/main/java/de/diddiz/LogBlock/Updater.java | 66 +++++++++++-------- 2 files changed, 63 insertions(+), 32 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 0e31eff..4e682f6 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -1,7 +1,27 @@ package de.diddiz.LogBlock; import de.diddiz.LogBlock.config.Config; -import de.diddiz.LogBlock.listeners.*; +import de.diddiz.LogBlock.listeners.BanListener; +import de.diddiz.LogBlock.listeners.BlockBreakLogging; +import de.diddiz.LogBlock.listeners.BlockBurnLogging; +import de.diddiz.LogBlock.listeners.BlockPlaceLogging; +import de.diddiz.LogBlock.listeners.BlockSpreadLogging; +import de.diddiz.LogBlock.listeners.ChatLogging; +import de.diddiz.LogBlock.listeners.ChestAccessLogging; +import de.diddiz.LogBlock.listeners.CreatureInteractLogging; +import de.diddiz.LogBlock.listeners.EndermenLogging; +import de.diddiz.LogBlock.listeners.ExplosionLogging; +import de.diddiz.LogBlock.listeners.FluidFlowLogging; +import de.diddiz.LogBlock.listeners.InteractLogging; +import de.diddiz.LogBlock.listeners.KillLogging; +import de.diddiz.LogBlock.listeners.LeavesDecayLogging; +import de.diddiz.LogBlock.listeners.PlayerInfoLogging; +import de.diddiz.LogBlock.listeners.SignChangeLogging; +import de.diddiz.LogBlock.listeners.SnowFadeLogging; +import de.diddiz.LogBlock.listeners.SnowFormLogging; +import de.diddiz.LogBlock.listeners.StructureGrowLogging; +import de.diddiz.LogBlock.listeners.ToolListener; +import de.diddiz.LogBlock.listeners.WitherLogging; import de.diddiz.util.MySQLConnectionPool; import de.diddiz.worldedit.LogBlockEditSessionFactory; import org.bukkit.ChatColor; @@ -94,11 +114,11 @@ public class LogBlock extends JavaPlugin commandsHandler = new CommandsHandler(this); getCommand("lb").setExecutor(commandsHandler); if (enableAutoClearLog && autoClearLogDelay > 0) - getServer().getScheduler().scheduleAsyncRepeatingTask(this, new AutoClearLog(this), 6000, autoClearLogDelay * 60 * 20); - getServer().getScheduler().scheduleAsyncDelayedTask(this, new DumpedLogImporter(this)); + getServer().getScheduler().runTaskTimerAsynchronously(this, new AutoClearLog(this), 6000, autoClearLogDelay * 60 * 20); + getServer().getScheduler().runTaskAsynchronously(this, new DumpedLogImporter(this)); registerEvents(); if (useBukkitScheduler) { - if (getServer().getScheduler().scheduleAsyncRepeatingTask(this, consumer, delayBetweenRuns * 20, delayBetweenRuns * 20) > 0) + if (getServer().getScheduler().runTaskTimerAsynchronously(this, consumer, delayBetweenRuns * 20, delayBetweenRuns * 20).getTaskId() > 0) getLogger().info("Scheduled consumer with bukkit scheduler."); else { getLogger().warning("Failed to schedule consumer with bukkit scheduler. Now trying schedule with timer."); @@ -110,6 +130,7 @@ public class LogBlock extends JavaPlugin timer.scheduleAtFixedRate(consumer, delayBetweenRuns * 1000, delayBetweenRuns * 1000); getLogger().info("Scheduled consumer with timer."); } + getServer().getScheduler().runTaskAsynchronously(this, new Updater.PlayerCountChecker(this)); for (final Tool tool : toolsByType.values()) if (pm.getPermission("logblock.tools." + tool.name) == null) { final Permission perm = new Permission("logblock.tools." + tool.name, tool.permissionDefault); diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 01fe971..3888aa2 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -1,9 +1,10 @@ package de.diddiz.LogBlock; -import static de.diddiz.LogBlock.config.Config.getLoggedWorlds; -import static de.diddiz.LogBlock.config.Config.isLogging; -import static de.diddiz.util.BukkitUtils.friendlyWorldname; -import static org.bukkit.Bukkit.getLogger; +import de.diddiz.LogBlock.config.WorldConfig; +import org.bukkit.Bukkit; +import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.configuration.file.YamlConfiguration; + import java.io.File; import java.io.IOException; import java.sql.Connection; @@ -12,10 +13,11 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.logging.Level; -import org.bukkit.Bukkit; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.YamlConfiguration; -import de.diddiz.LogBlock.config.WorldConfig; + +import static de.diddiz.LogBlock.config.Config.getLoggedWorlds; +import static de.diddiz.LogBlock.config.Config.isLogging; +import static de.diddiz.util.BukkitUtils.friendlyWorldname; +import static org.bukkit.Bukkit.getLogger; class Updater { @@ -197,26 +199,6 @@ class Updater } config.set("version", "1.52"); } - this.logblock.getServer().getScheduler().runTaskAsynchronously(this.logblock, new Thread() { - - @Override - public void run() { - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - ResultSet rs = st.executeQuery("SELECT auto_increment FROM information_schema.columns AS col join information_schema.tables AS tab ON (col.table_schema=tab.table_schema AND col.table_name=tab.table_name) WHERE col.table_name = 'lb-players' AND col.column_name = 'playerid' AND col.data_type = 'smallint' AND col.table_schema = DATABASE() AND auto_increment > 65000;"); - if (rs.next()) { - logblock.getLogger().warning("Your server reached 65000 players. You should soon update your database table schema - see FAQ: https://github.com/LogBlock/LogBlock/wiki/FAQ#logblock-your-server-reached-65000-players-"); - } - st.close(); - conn.close(); - } catch (final SQLException ex) { - logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - } - } - - }); logblock.saveConfig(); return true; } @@ -250,4 +232,32 @@ class Updater throw new SQLException("Table " + table + " not found and failed to create"); } } + + public static class PlayerCountChecker implements Runnable { + + private LogBlock logblock; + + public PlayerCountChecker(LogBlock logblock) { + this.logblock = logblock; + } + + @Override + public void run() { + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + ResultSet rs = st.executeQuery("SELECT auto_increment FROM information_schema.columns AS col join information_schema.tables AS tab ON (col.table_schema=tab.table_schema AND col.table_name=tab.table_name) WHERE col.table_name = 'lb-players' AND col.column_name = 'playerid' AND col.data_type = 'smallint' AND col.table_schema = DATABASE() AND auto_increment > 65000;"); + if (rs.next()) { + for (int i = 0; i < 6; i++) { + logblock.getLogger().warning("Your server reached 65000 players. You should soon update your database table schema - see FAQ: https://github.com/LogBlock/LogBlock/wiki/FAQ#logblock-your-server-reached-65000-players-"); + } + } + st.close(); + conn.close(); + } catch (final SQLException ex) { + logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + } + } + } } From aa09891f21ed05800b38dea57f99036f9cf18dd0 Mon Sep 17 00:00:00 2001 From: Marcos Vives Del Sol Date: Thu, 26 Sep 2013 13:16:22 +0200 Subject: [PATCH 05/50] Added logging of Locked Chest decay --- .../java/de/diddiz/LogBlock/LogBlock.java | 3 +++ src/main/java/de/diddiz/LogBlock/Logging.java | 2 +- .../listeners/LockedChestDecayLogging.java | 24 +++++++++++++++++++ 3 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 src/main/java/de/diddiz/LogBlock/listeners/LockedChestDecayLogging.java diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 4e682f6..86df1b0 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -15,6 +15,7 @@ import de.diddiz.LogBlock.listeners.FluidFlowLogging; import de.diddiz.LogBlock.listeners.InteractLogging; import de.diddiz.LogBlock.listeners.KillLogging; import de.diddiz.LogBlock.listeners.LeavesDecayLogging; +import de.diddiz.LogBlock.listeners.LockedChestDecayLogging; import de.diddiz.LogBlock.listeners.PlayerInfoLogging; import de.diddiz.LogBlock.listeners.SignChangeLogging; import de.diddiz.LogBlock.listeners.SnowFadeLogging; @@ -187,6 +188,8 @@ public class LogBlock extends JavaPlugin pm.registerEvents(new StructureGrowLogging(this), this); if (isLogging(Logging.GRASSGROWTH) || isLogging(Logging.MYCELIUMSPREAD) || isLogging(Logging.VINEGROWTH) || isLogging(Logging.MUSHROOMSPREAD)) pm.registerEvents(new BlockSpreadLogging(this), this); + if (isLogging(Logging.LOCKEDCHESTDECAY)) + pm.registerEvents(new LockedChestDecayLogging(this), this); if (logPlayerInfo) pm.registerEvents(new PlayerInfoLogging(this), this); } diff --git a/src/main/java/de/diddiz/LogBlock/Logging.java b/src/main/java/de/diddiz/LogBlock/Logging.java index de0c817..80e2f6d 100644 --- a/src/main/java/de/diddiz/LogBlock/Logging.java +++ b/src/main/java/de/diddiz/LogBlock/Logging.java @@ -9,7 +9,7 @@ public enum Logging PRESUREPLATEINTERACT, TRIPWIREINTERACT, CREATURECROPTRAMPLE, CROPTRAMPLE, NATURALSTRUCTUREGROW, GRASSGROWTH, MYCELIUMSPREAD, VINEGROWTH, MUSHROOMSPREAD, WITHER(true), WITHER_SKULL(true), BONEMEALSTRUCTUREGROW, - WORLDEDIT, TNTMINECARTEXPLOSION(true); + WORLDEDIT, TNTMINECARTEXPLOSION(true), LOCKEDCHESTDECAY; public static final int length = Logging.values().length; private final boolean defaultEnabled; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/LockedChestDecayLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/LockedChestDecayLogging.java new file mode 100644 index 0000000..5d3b113 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/listeners/LockedChestDecayLogging.java @@ -0,0 +1,24 @@ +package de.diddiz.LogBlock.listeners; + +import static de.diddiz.LogBlock.config.Config.isLogging; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockFadeEvent; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; + +public class LockedChestDecayLogging extends LoggingListener +{ + public LockedChestDecayLogging(LogBlock lb) { + super(lb); + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onBlockFade(BlockFadeEvent event) { + if (isLogging(event.getBlock().getWorld(), Logging.LOCKEDCHESTDECAY)) { + final int type = event.getBlock().getTypeId(); + if (type == 95) + consumer.queueBlockReplace("LockedChestDecay", event.getBlock().getState(), event.getNewState()); + } + } +} From 3c75ed1cbb230c2095c31db7e6fd67ae09412672 Mon Sep 17 00:00:00 2001 From: Sahir Date: Thu, 10 Oct 2013 19:19:39 -0400 Subject: [PATCH 06/50] More specific information when no params/args specified This commit adds the ArrayIndexOutOfBoundsException to onCommand's exception-catcher. This is so the user gets more specific information than "Error, check server.log" when they don't give any arguments. --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index a8aadb2..6f09c53 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -306,6 +306,8 @@ public class CommandsHandler implements CommandExecutor } } catch (final IllegalArgumentException ex) { sender.sendMessage(ChatColor.RED + ex.getMessage()); + } catch (final ArrayIndexOutOfBoundsException ex) { + sender.sendMessage(ChatColor.RED + "Not enough arguments given"); } catch (final Exception ex) { sender.sendMessage(ChatColor.RED + "Error, check server.log"); getLogger().log(Level.WARNING, "Exception in commands handler: ", ex); From 97be730fa84a11fbc33550c9ca63b22f15de46f8 Mon Sep 17 00:00:00 2001 From: md-5 Date: Fri, 18 Oct 2013 07:36:21 +1100 Subject: [PATCH 07/50] Maven deploy --- pom.xml | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/pom.xml b/pom.xml index f8e3766..0e620a1 100644 --- a/pom.xml +++ b/pom.xml @@ -1,4 +1,3 @@ - 4.0.0 @@ -28,18 +27,16 @@ http://ci.kitteh.org/job/LogBlock - - - kittehReleases - Kitteh Releases - http://repo.kitteh.org/content/repositories/releases - - - kittehSnapshots - Kitteh Snapshots - http://repo.kitteh.org/content/repositories/snapshots - - + + + md_5-releases + http://repo.md-5.net/content/repositories/releases/ + + + md_5-snapshots + http://repo.md-5.net/content/repositories/snapshots/ + + From c117bcd8543a9a6e4e1cf2984b820fff9a4e44c2 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Tue, 5 Nov 2013 21:09:14 +0000 Subject: [PATCH 08/50] Minor database change - Text fields should be UTF-8. Fixes #491 --- src/main/java/de/diddiz/LogBlock/Updater.java | 39 ++++++++++++++++++- src/main/resources/plugin.yml | 2 +- 2 files changed, 38 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 3888aa2..8de1123 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -199,6 +199,41 @@ class Updater } config.set("version", "1.52"); } + // Ensure charset for free-text fields is UTF-8 + // As this may be an expensive operation and the database default may already be UTF-8, check on a table-by-table basis before converting + if (config.getString("version").compareTo("1.71") < 0) { + getLogger().info("Updating tables to 1.71 ..."); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + if (isLogging(Logging.CHAT)) { + final ResultSet rs = st.executeQuery("SHOW FULL COLUMNS FROM `lb-chat` WHERE field = 'message'"); + if (rs.next() && !rs.getString("Collation").substring(0,4).equalsIgnoreCase("utf8")) { + st.execute("ALTER TABLE `lb-chat` CONVERT TO CHARSET utf8"); + getLogger().info("Table lb-chat modified"); + } else { + getLogger().info("Table lb-chat already fine, skipping it"); + } + } + for (final WorldConfig wcfg : getLoggedWorlds()) { + final ResultSet rs = st.executeQuery("SHOW FULL COLUMNS FROM `"+wcfg.table+"-sign` WHERE field = 'signtext'"); + if (rs.next() && !rs.getString("Collation").substring(0,4).equalsIgnoreCase("utf8")) { + st.execute("ALTER TABLE `"+wcfg.table+"-sign` CONVERT TO CHARSET utf8"); + getLogger().info("Table "+wcfg.table+"-sign modified"); + } else { + getLogger().info("Table "+wcfg.table+"-sign already fine, skipping it"); + } + } + st.close(); + conn.close(); + } catch (final SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.71"); + } + logblock.saveConfig(); return true; } @@ -212,10 +247,10 @@ class Updater conn.setAutoCommit(true); createTable(dbm, state, "lb-players", "(playerid INT UNSIGNED NOT NULL AUTO_INCREMENT, playername varchar(32) NOT NULL, firstlogin DATETIME NOT NULL, lastlogin DATETIME NOT NULL, onlinetime INT UNSIGNED NOT NULL, ip varchar(255) NOT NULL, PRIMARY KEY (playerid), UNIQUE (playername))"); if (isLogging(Logging.CHAT)) - createTable(dbm, state, "lb-chat", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, message VARCHAR(255) NOT NULL, PRIMARY KEY (id), KEY playerid (playerid), FULLTEXT message (message)) ENGINE=MyISAM"); + createTable(dbm, state, "lb-chat", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, message VARCHAR(255) NOT NULL, PRIMARY KEY (id), KEY playerid (playerid), FULLTEXT message (message)) ENGINE=MyISAM DEFAULT CHARSET utf8"); for (final WorldConfig wcfg : getLoggedWorlds()) { createTable(dbm, state, wcfg.table, "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced TINYINT UNSIGNED NOT NULL, type TINYINT UNSIGNED NOT NULL, data TINYINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))"); - createTable(dbm, state, wcfg.table + "-sign", "(id INT UNSIGNED NOT NULL, signtext VARCHAR(255) NOT NULL, PRIMARY KEY (id))"); + createTable(dbm, state, wcfg.table + "-sign", "(id INT UNSIGNED NOT NULL, signtext VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET utf8"); createTable(dbm, state, wcfg.table + "-chest", "(id INT UNSIGNED NOT NULL, itemtype SMALLINT UNSIGNED NOT NULL, itemamount SMALLINT NOT NULL, itemdata TINYINT UNSIGNED NOT NULL, PRIMARY KEY (id))"); if (wcfg.isLogging(Logging.KILL)) createTable(dbm, state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x SMALLINT NOT NULL, y TINYINT UNSIGNED NOT NULL, z SMALLINT NOT NULL, PRIMARY KEY (id))"); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 637fe4e..ce1095d 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: ${project.name} -version: '1.70' +version: '1.71' author: DiddiZ authors: [md_5, ammar2] website: http://dev.bukkit.org/server-mods/logblock/ From 7ac35e46985707516f8b73778156baf6e733483b Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Wed, 6 Nov 2013 10:45:13 +0000 Subject: [PATCH 09/50] Alter INSERT IGNORE queries to workaround innodb auto increment behaviour An INSERT IGNORE query will still increment when using innodb, even if no row is inserted. We can work around this by using a slightly convoluted query, but this only works if the table is non-empty, so also check for that on startup and create a dummy record if necessary. --- src/main/java/de/diddiz/LogBlock/Consumer.java | 6 ++++-- src/main/java/de/diddiz/LogBlock/Updater.java | 4 ++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 48d8ff2..e1fb205 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -336,7 +336,8 @@ public class Consumer extends TimerTask continue; for (final String player : r.getPlayers()) if (!playerIds.containsKey(player) && !insertedPlayers.contains(player)) { - writer.println("INSERT IGNORE INTO `lb-players` (playername) VALUES ('" + player + "');"); + // Odd query contruction is to work around innodb auto increment behaviour - bug #492 + writer.println("INSERT IGNORE INTO `lb-players` (playername) SELECT '" + player + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE playername = '" + player + "') LIMIT 1;"); insertedPlayers.add(player); } for (final String insert : r.getInserts()) @@ -365,7 +366,8 @@ public class Consumer extends TimerTask } private boolean addPlayer(Statement state, String playerName) throws SQLException { - state.execute("INSERT IGNORE INTO `lb-players` (playername) VALUES ('" + playerName + "')"); + // Odd query contruction is to work around innodb auto increment behaviour - bug #492 + state.execute("INSERT IGNORE INTO `lb-players` (playername) SELECT '" + playerName + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE playername = '" + playerName + "') LIMIT 1;"); final ResultSet rs = state.executeQuery("SELECT playerid FROM `lb-players` WHERE playername = '" + playerName + "'"); if (rs.next()) playerIds.put(playerName, rs.getInt(1)); diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 8de1123..6d35c79 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -246,6 +246,10 @@ class Updater final DatabaseMetaData dbm = conn.getMetaData(); conn.setAutoCommit(true); createTable(dbm, state, "lb-players", "(playerid INT UNSIGNED NOT NULL AUTO_INCREMENT, playername varchar(32) NOT NULL, firstlogin DATETIME NOT NULL, lastlogin DATETIME NOT NULL, onlinetime INT UNSIGNED NOT NULL, ip varchar(255) NOT NULL, PRIMARY KEY (playerid), UNIQUE (playername))"); + // Players table must not be empty or inserts won't work - bug #492 + final ResultSet rs = state.executeQuery("SELECT NULL FROM `lb-players` LIMIT 1;"); + if (!rs.next()) + state.execute("INSERT IGNORE INTO `lb-players` (playername) VALUES ('dummy_record')"); if (isLogging(Logging.CHAT)) createTable(dbm, state, "lb-chat", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, message VARCHAR(255) NOT NULL, PRIMARY KEY (id), KEY playerid (playerid), FULLTEXT message (message)) ENGINE=MyISAM DEFAULT CHARSET utf8"); for (final WorldConfig wcfg : getLoggedWorlds()) { From 6025469dfab1accbadbb0514249fb037d3ae0bea Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Thu, 7 Nov 2013 13:51:02 +0000 Subject: [PATCH 10/50] Expand chestaccess querying Make a decison on whether or not to return chest access data based on the BlockChangeType (ALL or CHESTACCESS) rather than partly on the block parameter as these are the only two query types that don't enforce type != replaced This is helpful because the list of blocks to request chest access for was outdated and is duplicated in 3 different places, whereas the new method will return whatever results have been logged regardless of type. In addition, if the query type is CHESTACCESS (but not ALL), we can use an alternate query that is vastly more efficient. In tests (26 million row log table, 400,000 row chest table) the query time for all chest results was reduced from 30 seconds to 3. Allows the chestaccess parameter to return data from the following inventory types: - Brewing stand - Trapped chest (fixes #483) - Dropper - Hopper - Beacon Note that this only affects lookup of logged items; the logging process has not been touched, so #433 and similar have not been addressed Also, update the list of valid container types, which will improve logging of broken containers. --- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 7 +++---- src/main/java/de/diddiz/LogBlock/Consumer.java | 6 +++--- src/main/java/de/diddiz/LogBlock/QueryParams.java | 8 ++++++-- src/main/java/de/diddiz/util/BukkitUtils.java | 2 ++ 4 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 6f09c53..b3c8039 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -406,7 +406,7 @@ public class CommandsHandler implements CommandExecutor params.needPlayer = true; if (params.types.isEmpty() || Block.inList(params.types, 63) || Block.inList(params.types, 68)) params.needSignText = true; - if (params.bct == BlockChangeType.CHESTACCESS || params.types.isEmpty() || Block.inList(params.types, 23) || Block.inList(params.types, 54) || Block.inList(params.types, 61) || Block.inList(params.types, 62)) + if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) params.needChestAccess = true; } conn = logblock.getConnection(); @@ -466,7 +466,7 @@ public class CommandsHandler implements CommandExecutor params.needPlayer = true; if (params.types.isEmpty() || Block.inList(params.types, 63) || Block.inList(params.types, 68)) params.needSignText = true; - if (params.types.isEmpty() || Block.inList(params.types, 23) || Block.inList(params.types, 54) || Block.inList(params.types, 61) || Block.inList(params.types, 62)) + if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) params.needChestAccess = true; } conn = logblock.getConnection(); @@ -538,9 +538,8 @@ public class CommandsHandler implements CommandExecutor public void run() { try { params.needCoords = true; - if (params.bct == BlockChangeType.CHESTACCESS || params.types.isEmpty() || Block.inList(params.types, 23) || Block.inList(params.types, 54) || Block.inList(params.types, 61) || Block.inList(params.types, 62)) { + if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) params.needChestAccess = true; - } params.limit = 1; params.sum = SummarizationMode.NONE; conn = logblock.getConnection(); diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index e1fb205..5938ce7 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -120,7 +120,7 @@ public class Consumer extends TimerTask /** * @param container - * The respective container. Must be an instance of Chest, Dispencer or Furnace. + * The respective container. Must be an instance of an InventoryHolder. */ public void queueChestAccess(String playerName, BlockState container, short itemType, short itemAmount, byte itemData) { if (!(container instanceof InventoryHolder)) @@ -130,7 +130,7 @@ public class Consumer extends TimerTask /** * @param type - * Type id of the container. Must be 63 or 68. + * Type id of the container. */ public void queueChestAccess(String playerName, Location loc, int type, short itemType, short itemAmount, byte itemData) { queueBlock(playerName, loc, type, type, (byte)0, null, new ChestAccess(itemType, itemAmount, itemData)); @@ -140,7 +140,7 @@ public class Consumer extends TimerTask * Logs a container block break. The block type before is assumed to be o (air). All content is assumed to be taken. * * @param container - * Must be instanceof InventoryHolder + * Must be an instance of InventoryHolder */ public void queueContainerBreak(String playerName, BlockState container) { if (!(container instanceof InventoryHolder)) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 964aa3e..01f0b56 100755 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -141,7 +141,12 @@ public final class QueryParams implements Cloneable if (needSignText) from += "LEFT JOIN `" + getTable() + "-sign` USING (id) "; if (needChestAccess) - from += "LEFT JOIN `" + getTable() + "-chest` USING (id) "; + // If BlockChangeType is CHESTACCESS, we can use more efficient query + if (bct == BlockChangeType.CHESTACCESS) { + from += "RIGHT JOIN `" + getTable() + "-chest` USING (id) "; + } else { + from += "LEFT JOIN `" + getTable() + "-chest` USING (id) "; + } return select + " " + from + getWhere() + "ORDER BY date " + order + ", id " + order + " " + getLimit(); } else if (sum == SummarizationMode.TYPES) return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.CREATED) + "GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); @@ -367,7 +372,6 @@ public final class QueryParams implements Cloneable where.append("type != replaced AND "); break; case CHESTACCESS: - where.append("(type = 23 OR type = 54 OR type = 61 OR type = 62) AND type = replaced AND "); if (!types.isEmpty()) { where.append('('); for (final Block block : types) { diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index b3c7041..59f45a7 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -152,6 +152,8 @@ public class BukkitUtils containerBlocks.add(Material.DROPPER); containerBlocks.add(Material.HOPPER); containerBlocks.add(Material.BREWING_STAND); + containerBlocks.add(Material.FURNACE); + containerBlocks.add(Material.BEACON); // Doesn't actually have a block inventory // containerBlocks.add(Material.ENDER_CHEST); } From 6992a4ffa8322f3de4b4ffeb8fc77ab51e7df299 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Fri, 8 Nov 2013 10:32:13 +0000 Subject: [PATCH 11/50] Enchance inventory access log output message As there are more inventory types now, it is worthwhile including the inventory name in the output e.g: 11-07 20:47:15 frymaster took 64x iron ingot from furnace 11-07 13:42:14 frymaster put 1x iron ingot into beacon --- src/main/java/de/diddiz/LogBlock/BlockChange.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 3e839c4..0af5ea6 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -64,9 +64,9 @@ public class BlockChange implements LookupCacheElement if (ca.itemType == 0 || ca.itemAmount == 0) msg.append("looked inside ").append(materialName(type)); else if (ca.itemAmount < 0) - msg.append("took ").append(-ca.itemAmount).append("x ").append(materialName(ca.itemType, ca.itemData)); + msg.append("took ").append(-ca.itemAmount).append("x ").append(materialName(ca.itemType, ca.itemData)).append(" from ").append(materialName(type)); else - msg.append("put in ").append(ca.itemAmount).append("x ").append(materialName(ca.itemType, ca.itemData)); + msg.append("put ").append(ca.itemAmount).append("x ").append(materialName(ca.itemType, ca.itemData)).append(" into ").append(materialName(type)); } else if (BukkitUtils.getContainerBlocks().contains(Material.getMaterial(type))) msg.append("opened ").append(materialName(type)); else if (type == 64 || type == 71) From 8c9f78a985e8db19cff7dbd3945cfe4ce174e4c4 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Fri, 8 Nov 2013 10:32:13 +0000 Subject: [PATCH 12/50] Enchance inventory access log output message As there are more inventory types now, it is worthwhile including the inventory name in the output e.g: 11-07 20:47:15 frymaster took 64x iron ingot from furnace 11-07 13:42:14 frymaster put 1x iron ingot into beacon --- src/main/java/de/diddiz/LogBlock/BlockChange.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 3e839c4..0af5ea6 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -64,9 +64,9 @@ public class BlockChange implements LookupCacheElement if (ca.itemType == 0 || ca.itemAmount == 0) msg.append("looked inside ").append(materialName(type)); else if (ca.itemAmount < 0) - msg.append("took ").append(-ca.itemAmount).append("x ").append(materialName(ca.itemType, ca.itemData)); + msg.append("took ").append(-ca.itemAmount).append("x ").append(materialName(ca.itemType, ca.itemData)).append(" from ").append(materialName(type)); else - msg.append("put in ").append(ca.itemAmount).append("x ").append(materialName(ca.itemType, ca.itemData)); + msg.append("put ").append(ca.itemAmount).append("x ").append(materialName(ca.itemType, ca.itemData)).append(" into ").append(materialName(type)); } else if (BukkitUtils.getContainerBlocks().contains(Material.getMaterial(type))) msg.append("opened ").append(materialName(type)); else if (type == 64 || type == 71) From eb84fd1380809abb7ab64a5d0825a3f7be90fff3 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Fri, 8 Nov 2013 13:56:05 +0000 Subject: [PATCH 13/50] Various minor improvements to querying and logging - Allow use of "both" as a query parameter. This will search for created and destroyed blocks, but not chestaccess. This is useful for situations where the query defaults to "all" e.g. rollbacks. Fixes #210, #252 - Add block negation query parameter. Like with player names, you can now precede a block name with "!" to query for all except the specified blocks. Fixes #452, #216 - Allow use of area parameter with location parameter, as long as location is specified first. Fixes #458 - Better error when asking for kill log without world specified - Don't try to process events where the block is null. Fixes #463 - Replace problematic characters in world names with underscores when deciding on a default table name. Fixes #409 - Adjust for cocoa beans having reversed attachment direction in smart logging - Prevent out of bounds exception if a single-word timespec ends in a number. Fixes #354 - Prevent error when specifying a killer or victim in a teleport lookup. Fixes #333 --- .../de/diddiz/LogBlock/CommandsHandler.java | 4 +- .../java/de/diddiz/LogBlock/QueryParams.java | 56 +++++++++++++------ .../diddiz/LogBlock/config/WorldConfig.java | 4 +- .../LogBlock/listeners/InteractLogging.java | 1 + src/main/java/de/diddiz/util/LoggingUtil.java | 2 +- src/main/java/de/diddiz/util/Utils.java | 2 + 6 files changed, 49 insertions(+), 20 deletions(-) mode change 100755 => 100644 src/main/java/de/diddiz/LogBlock/QueryParams.java diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index b3c8039..16cbf56 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -551,8 +551,8 @@ public class CommandsHandler implements CommandExecutor rs = state.executeQuery(params.getQuery()); if (rs.next()) { final Player player = (Player)sender; - final int y = rs.getInt(2); - final Location loc = new Location(params.world, rs.getInt(1) + 0.5, y, rs.getInt(3) + 0.5, player.getLocation().getYaw(), 90); + final int y = rs.getInt("y"); + final Location loc = new Location(params.world, rs.getInt("x") + 0.5, y, rs.getInt("z") + 0.5, player.getLocation().getYaw(), 90); // Teleport the player sync because omg thread safety logblock.getServer().getScheduler().scheduleSyncDelayedTask(logblock, new Runnable() { diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java old mode 100755 new mode 100644 index 01f0b56..4de1977 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -24,7 +24,7 @@ import static de.diddiz.util.Utils.*; public final class QueryParams implements Cloneable { - private static final Set keywords = new HashSet(Arrays.asList("player".hashCode(), "area".hashCode(), "selection".hashCode(), "sel".hashCode(), "block".hashCode(), "type".hashCode(), "sum".hashCode(), "destroyed".hashCode(), "created".hashCode(), "chestaccess".hashCode(), "all".hashCode(), "time".hashCode(), "since".hashCode(), "before".hashCode(), "limit".hashCode(), "world".hashCode(), "asc".hashCode(), "desc".hashCode(), "last".hashCode(), "coords".hashCode(), "silent".hashCode(), "chat".hashCode(), "search".hashCode(), "match".hashCode(), "loc".hashCode(), "location".hashCode(), "kills".hashCode(), "killer".hashCode(), "victim".hashCode())); + private static final Set keywords = new HashSet(Arrays.asList("player".hashCode(), "area".hashCode(), "selection".hashCode(), "sel".hashCode(), "block".hashCode(), "type".hashCode(), "sum".hashCode(), "destroyed".hashCode(), "created".hashCode(), "chestaccess".hashCode(), "all".hashCode(), "time".hashCode(), "since".hashCode(), "before".hashCode(), "limit".hashCode(), "world".hashCode(), "asc".hashCode(), "desc".hashCode(), "last".hashCode(), "coords".hashCode(), "silent".hashCode(), "chat".hashCode(), "search".hashCode(), "match".hashCode(), "loc".hashCode(), "location".hashCode(), "kills".hashCode(), "killer".hashCode(), "victim".hashCode(), "both".hashCode())); public BlockChangeType bct = BlockChangeType.BOTH; public int limit = -1, before = 0, since = 0, radius = -1; public Location loc = null; @@ -32,7 +32,7 @@ public final class QueryParams implements Cloneable public List players = new ArrayList(); public List killers = new ArrayList(); public List victims = new ArrayList(); - public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, prepareToolQuery = false, silent = false; + public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, excludeBlocksMode = false, prepareToolQuery = false, silent = false; public RegionContainer sel = null; public SummarizationMode sum = SummarizationMode.NONE; public List types = new ArrayList(); @@ -168,6 +168,8 @@ public final class QueryParams implements Cloneable title.append("kills "); else { if (!types.isEmpty()) { + if (excludeBlocksMode) + title.append("all blocks except "); final String[] blocknames = new String[types.size()]; for (int i = 0; i < types.size(); i++) blocknames[i] = materialName(types.get(i).getBlock()); @@ -203,7 +205,7 @@ public final class QueryParams implements Cloneable title.append("more than ").append(before * -1).append(" minutes ago "); if (loc != null) { if (radius > 0) - title.append("within ").append(radius).append(" blocks of ").append(prepareToolQuery ? "clicked block" : "you").append(" "); + title.append("within ").append(radius).append(" blocks of ").append(prepareToolQuery ? "clicked block" : "location").append(" "); else if (radius == 0) title.append("at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ()).append(" "); } else if (sel != null) @@ -304,6 +306,8 @@ public final class QueryParams implements Cloneable switch (blockChangeType) { case ALL: if (!types.isEmpty()) { + if (excludeBlocksMode) + where.append("NOT "); where.append('('); for (final Block block : types) { where.append("((type = ").append(block.getBlock()).append(" OR replaced = ").append(block.getBlock()); @@ -320,6 +324,8 @@ public final class QueryParams implements Cloneable break; case BOTH: if (!types.isEmpty()) { + if (excludeBlocksMode) + where.append("NOT "); where.append('('); for (final Block block : types) { where.append("((type = ").append(block.getBlock()).append(" OR replaced = ").append(block.getBlock()); @@ -337,6 +343,8 @@ public final class QueryParams implements Cloneable break; case CREATED: if (!types.isEmpty()) { + if (excludeBlocksMode) + where.append("NOT "); where.append('('); for (final Block block : types) { where.append("((type = ").append(block.getBlock()); @@ -349,12 +357,13 @@ public final class QueryParams implements Cloneable } where.delete(where.length() - 4, where.length()); where.append(") AND "); - } else - where.append("type != 0 AND "); - where.append("type != replaced AND "); + } + where.append("type != 0 AND type != replaced AND "); break; case DESTROYED: if (!types.isEmpty()) { + if (excludeBlocksMode) + where.append("NOT "); where.append('('); for (final Block block : types) { where.append("((replaced = ").append(block.getBlock()); @@ -367,12 +376,13 @@ public final class QueryParams implements Cloneable } where.delete(where.length() - 4, where.length()); where.append(") AND "); - } else - where.append("replaced != 0 AND "); - where.append("type != replaced AND "); + } + where.append("replaced != 0 AND type != replaced AND "); break; case CHESTACCESS: if (!types.isEmpty()) { + if (excludeBlocksMode) + where.append("NOT "); where.append('('); for (final Block block : types) { where.append("((itemtype = ").append(block.getBlock()); @@ -492,6 +502,7 @@ public final class QueryParams implements Cloneable players.add(matches.size() == 1 ? matches.get(0).getName() : playerName.replaceAll("[^a-zA-Z0-9_]", "")); } } + needPlayer = true; } else if (param.equals("killer")) { if (values.length < 1) throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); @@ -508,6 +519,7 @@ public final class QueryParams implements Cloneable killers.add(matches.size() == 1 ? matches.get(0).getName() : killerName.replaceAll("[^a-zA-Z0-9_]", "")); } } + needKiller = true; } else if (param.equals("victim")) { if (values.length < 1) throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); @@ -524,6 +536,7 @@ public final class QueryParams implements Cloneable victims.add(matches.size() == 1 ? matches.get(0).getName() : victimName.replaceAll("[^a-zA-Z0-9_]", "")); } } + needVictim = true; } else if (param.equals("weapon")) { if (values.length < 1) throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); @@ -539,10 +552,15 @@ public final class QueryParams implements Cloneable throw new IllegalArgumentException("No material matching: '" + weaponName + "'"); types.add(new Block(mat.getId(), -1)); } + needWeapon = true; } else if (param.equals("block") || param.equals("type")) { if (values.length < 1) throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'"); - for (final String blockName : values) { + for (String blockName : values) { + if (blockName.startsWith("!")) { + excludeBlocksMode = true; + blockName = blockName.substring(1); + } if (blockName.contains(":")) { String[] blockNameSplit = blockName.split(":"); if (blockNameSplit.length > 2) @@ -567,17 +585,17 @@ public final class QueryParams implements Cloneable } } } else if (param.equals("area")) { - if (player == null && !prepareToolQuery) - throw new IllegalArgumentException("You have to ba a player to use area"); + if (player == null && !prepareToolQuery && loc == null) + throw new IllegalArgumentException("You have to be a player to use area, or specify a location first"); if (values.length == 0) { radius = defaultDist; - if (!prepareToolQuery) + if (!prepareToolQuery && loc == null) loc = player.getLocation(); } else { if (!isInt(values[0])) throw new IllegalArgumentException("Not a number: '" + values[0] + "'"); radius = Integer.parseInt(values[0]); - if (!prepareToolQuery) + if (!prepareToolQuery && loc == null) loc = player.getLocation(); } } else if (param.equals("selection") || param.equals("sel")) { @@ -612,6 +630,8 @@ public final class QueryParams implements Cloneable bct = BlockChangeType.CREATED; else if (param.equals("destroyed")) bct = BlockChangeType.DESTROYED; + else if (param.equals("both")) + bct = BlockChangeType.BOTH; else if (param.equals("chestaccess")) bct = BlockChangeType.CHESTACCESS; else if (param.equals("chat")) @@ -659,8 +679,12 @@ public final class QueryParams implements Cloneable throw new IllegalArgumentException("Not a valid argument: '" + param + "'"); i += values.length; } - if (bct == BlockChangeType.KILLS && !getWorldConfig(world).isLogging(Logging.KILL)) - throw new IllegalArgumentException("Kill logging not enabled for world '" + world.getName() + "'"); + if (bct == BlockChangeType.KILLS) { + if (world == null) + throw new IllegalArgumentException("No world specified"); + if (!getWorldConfig(world).isLogging(Logging.KILL)) + throw new IllegalArgumentException("Kill logging not enabled for world '" + world.getName() + "'"); + } if (types.size() > 0) for (final Set equivalent : getBlockEquivalents()) { boolean found = false; diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index ee81eda..1fef2d0 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -14,7 +14,9 @@ public class WorldConfig extends LoggingEnabledMapping public WorldConfig(File file) throws IOException { final Map def = new HashMap(); - def.put("table", "lb-" + file.getName().substring(0, file.getName().length() - 4).replace(' ', '_')); + // "Before MySQL 5.1.6, database and table names cannot contain "/", "\", ".", or characters that are not permitted in file names" - MySQL manual + // They _can_ contain spaces, but replace them as well + def.put("table", "lb-" + file.getName().substring(0, file.getName().length() - 4).replaceAll("[ ./\\\\]", "_")); for (final Logging l : Logging.values()) def.put("logging." + l.toString(), l.isDefaultEnabled()); final YamlConfiguration config = YamlConfiguration.loadConfiguration(file); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index 6caddb1..4c96dc2 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -27,6 +27,7 @@ public class InteractLogging extends LoggingListener final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld()); if (wcfg != null) { final Block clicked = event.getClickedBlock(); + if (clicked == null) return; final Material type = clicked.getType(); final int typeId = type.getId(); final byte blockData = clicked.getData(); diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index b53c6a8..5b905bb 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -109,7 +109,7 @@ public class LoggingUtil { } break; case COCOA: - if (blockState.getBlock().getRelative(((CocoaPlant) data).getAttachedFace()).equals(origin)) { + if (blockState.getBlock().getRelative(((CocoaPlant) data).getAttachedFace().getOppositeFace()).equals(origin)) { consumer.queueBlockBreak(playerName, blockState); } break; diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index 2929ce5..167dec7 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -76,6 +76,8 @@ public class Utils while (currIndex <= spec[0].length() && isInt(spec[0].substring(lastIndex, currIndex))) currIndex++; if (currIndex - 1 != lastIndex) { + if (currIndex > spec[0].length()) + return -1; final String param = spec[0].substring(currIndex - 1, currIndex).toLowerCase(); if (param.equals("d")) days = Integer.parseInt(spec[0].substring(lastIndex, currIndex - 1)); From ab53755eafad7906cd21b174723f395f8abb8dee Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Wed, 13 Nov 2013 12:00:22 +0000 Subject: [PATCH 14/50] Typo in config error message --- src/main/java/de/diddiz/LogBlock/config/Config.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index e93c861..5f69a96 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -147,7 +147,7 @@ public class Config try { logKillsLevel = LogKillsLevel.valueOf(config.getString("logging.logKillsLevel").toUpperCase()); } catch (final IllegalArgumentException ex) { - throw new DataFormatException("lookup.toolblockID doesn't appear to be a valid log level. Allowed are 'PLAYERS', 'MONSTERS' and 'ANIMALS'"); + throw new DataFormatException("logging.logKillsLevel doesn't appear to be a valid log level. Allowed are 'PLAYERS', 'MONSTERS' and 'ANIMALS'"); } hiddenPlayers = new HashSet(); for (final String playerName : config.getStringList("logging.hiddenPlayers")) From fa9a86a3b9b87dab344977958ea922c1de2752fd Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Wed, 13 Nov 2013 14:28:42 +0000 Subject: [PATCH 15/50] Implement logging for environmental (non-entity) kills, such as suffocation. Adds #80 This change adds a new config option, logEnvironmentalKills. When set to true, Logblock will record entity deaths not directly caused by another entity. (for example, suffocation, or burning to death) --- .../java/de/diddiz/LogBlock/Consumer.java | 19 ++++++++++++--- .../de/diddiz/LogBlock/config/Config.java | 3 +++ .../LogBlock/listeners/KillLogging.java | 24 +++++++++++++------ 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 5938ce7..4aa7558 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -160,9 +160,9 @@ public class Consumer extends TimerTask /** * @param killer - * Can' be null + * Can't be null * @param victim - * Can' be null + * Can't be null */ public void queueKill(Entity killer, Entity victim) { if (killer == null || victim == null) @@ -173,6 +173,19 @@ public class Consumer extends TimerTask queueKill(victim.getLocation(), entityName(killer), entityName(victim), weapon); } + /** + * This form should only be used when the killer is not an entity e.g. for fall or suffocation damage + * @param killer + * Can't be null + * @param victim + * Can't be null + */ + public void queueKill(String killer, Entity victim) { + if (killer == null || victim == null) + return; + queueKill(victim.getLocation(), killer, entityName(victim), 0); + } + /** * @param world * World the victim was inside. @@ -539,7 +552,7 @@ public class Consumer extends TimerTask @Override public String[] getInserts() { - return new String[]{"INSERT INTO `" + getWorldConfig(loc.getWorld()).table + "-kills` (date, killer, victim, weapon, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(killer) + ", " + playerID(victim) + ", " + weapon + ", " + loc.getBlockX() + ", " + loc.getBlockY() + ", " + loc.getBlockZ() + ");"}; + return new String[]{"INSERT INTO `" + getWorldConfig(loc.getWorld()).table + "-kills` (date, killer, victim, weapon, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(killer) + ", " + playerID(victim) + ", " + weapon + ", " + loc.getBlockX() + ", " + (loc.getBlockY() < 0 ? 0 : loc.getBlockY()) + ", " + loc.getBlockZ() + ");"}; } @Override diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 5f69a96..ff78a69 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -46,6 +46,7 @@ public class Config public static Set ignoredChat; public static SimpleDateFormat formatter; public static boolean safetyIdCheck; + public static boolean logEnvironmentalKills; public static enum LogKillsLevel { @@ -82,6 +83,7 @@ public class Config def.put("clearlog.autoClearLogDelay", "6h"); def.put("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false); def.put("logging.logKillsLevel", "PLAYERS"); + def.put("logging.logEnvironmentalKills", false); def.put("logging.logPlayerInfo", false); def.put("logging.hiddenPlayers", new ArrayList()); def.put("logging.hiddenBlocks", Arrays.asList(0)); @@ -149,6 +151,7 @@ public class Config } catch (final IllegalArgumentException ex) { throw new DataFormatException("logging.logKillsLevel doesn't appear to be a valid log level. Allowed are 'PLAYERS', 'MONSTERS' and 'ANIMALS'"); } + logEnvironmentalKills = config.getBoolean("logging.logEnvironmentalKills", false); hiddenPlayers = new HashSet(); for (final String playerName : config.getStringList("logging.hiddenPlayers")) hiddenPlayers.add(playerName.toLowerCase().trim()); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java index c4f8313..491ba34 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java @@ -2,6 +2,7 @@ package de.diddiz.LogBlock.listeners; import static de.diddiz.LogBlock.config.Config.isLogging; import static de.diddiz.LogBlock.config.Config.logKillsLevel; +import static de.diddiz.LogBlock.config.Config.logEnvironmentalKills; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Monster; @@ -15,6 +16,7 @@ import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.Config.LogKillsLevel; + public class KillLogging extends LoggingListener { @@ -26,14 +28,22 @@ public class KillLogging extends LoggingListener public void onEntityDeath(EntityDeathEvent deathEvent) { EntityDamageEvent event = deathEvent.getEntity().getLastDamageCause(); // For a death event, there should always be a damage event and it should not be cancelled. Check anyway. - if (event!= null && event.isCancelled() == false && isLogging(event.getEntity().getWorld(), Logging.KILL) && event instanceof EntityDamageByEntityEvent && event.getEntity() instanceof LivingEntity) { + if (event!= null && event.isCancelled() == false && isLogging(event.getEntity().getWorld(), Logging.KILL) && event.getEntity() instanceof LivingEntity) { final LivingEntity victim = (LivingEntity)event.getEntity(); - final Entity killer = ((EntityDamageByEntityEvent)event).getDamager(); - if (logKillsLevel == LogKillsLevel.PLAYERS && !(victim instanceof Player && killer instanceof Player)) - return; - else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster) && killer instanceof Player || killer instanceof Monster)) - return; - consumer.queueKill(killer, victim); + if (event instanceof EntityDamageByEntityEvent) { + final Entity killer = ((EntityDamageByEntityEvent)event).getDamager(); + if (logKillsLevel == LogKillsLevel.PLAYERS && !(victim instanceof Player && killer instanceof Player)) + return; + else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster) && killer instanceof Player || killer instanceof Monster)) + return; + consumer.queueKill(killer, victim); + } else if (logEnvironmentalKills) { + if (logKillsLevel == LogKillsLevel.PLAYERS && !(victim instanceof Player)) + return; + else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster))) + return; + consumer.queueKill(event.getCause().toString(),victim); + } } } } From d055d2af863601220eff8ee6b70b7e244e058533 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Wed, 4 Dec 2013 09:32:36 +0000 Subject: [PATCH 16/50] Increase width of kill table coordinate fields to mirror the block table increase --- src/main/java/de/diddiz/LogBlock/Updater.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 6d35c79..dd15b98 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -257,7 +257,7 @@ class Updater createTable(dbm, state, wcfg.table + "-sign", "(id INT UNSIGNED NOT NULL, signtext VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET utf8"); createTable(dbm, state, wcfg.table + "-chest", "(id INT UNSIGNED NOT NULL, itemtype SMALLINT UNSIGNED NOT NULL, itemamount SMALLINT NOT NULL, itemdata TINYINT UNSIGNED NOT NULL, PRIMARY KEY (id))"); if (wcfg.isLogging(Logging.KILL)) - createTable(dbm, state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x SMALLINT NOT NULL, y TINYINT UNSIGNED NOT NULL, z SMALLINT NOT NULL, PRIMARY KEY (id))"); + createTable(dbm, state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id))"); } state.close(); conn.close(); From d50c48f79da08beef287e0b8ddb6480db818a4f7 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Wed, 4 Dec 2013 09:45:38 +0000 Subject: [PATCH 17/50] Check sign text is being logged before attempting to update table --- src/main/java/de/diddiz/LogBlock/Updater.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index dd15b98..7691715 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -217,12 +217,14 @@ class Updater } } for (final WorldConfig wcfg : getLoggedWorlds()) { - final ResultSet rs = st.executeQuery("SHOW FULL COLUMNS FROM `"+wcfg.table+"-sign` WHERE field = 'signtext'"); - if (rs.next() && !rs.getString("Collation").substring(0,4).equalsIgnoreCase("utf8")) { - st.execute("ALTER TABLE `"+wcfg.table+"-sign` CONVERT TO CHARSET utf8"); - getLogger().info("Table "+wcfg.table+"-sign modified"); - } else { - getLogger().info("Table "+wcfg.table+"-sign already fine, skipping it"); + if (wcfg.isLogging(Logging.SIGNTEXT)) { + final ResultSet rs = st.executeQuery("SHOW FULL COLUMNS FROM `"+wcfg.table+"-sign` WHERE field = 'signtext'"); + if (rs.next() && !rs.getString("Collation").substring(0,4).equalsIgnoreCase("utf8")) { + st.execute("ALTER TABLE `"+wcfg.table+"-sign` CONVERT TO CHARSET utf8"); + getLogger().info("Table "+wcfg.table+"-sign modified"); + } else { + getLogger().info("Table "+wcfg.table+"-sign already fine, skipping it"); + } } } st.close(); From c0b983e8e8aa4fc76269d5655037652a84b66f42 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Wed, 4 Dec 2013 11:21:34 +0000 Subject: [PATCH 18/50] Allow for logging of item data greater than 256. Fixes #96, #235 This change involves refactoring many instances of "byte" to "short and altering a few ItemStack calls to use the int,int,short form instead of int,int,0,byte Significantly it also involves altering the MaterialName system to allow shorts instead of bytes, and altering the rawdata() function to return the durability of an ItemStack rather than the data value of its Material. One side effect of this is that tool durability is now logged, which will make for more accurate rollbacks. --- .../java/de/diddiz/LogBlock/ChestAccess.java | 5 ++--- .../de/diddiz/LogBlock/CommandsHandler.java | 2 +- .../java/de/diddiz/LogBlock/Consumer.java | 4 ++-- src/main/java/de/diddiz/LogBlock/Updater.java | 22 ++++++++++++++++++- .../java/de/diddiz/LogBlock/WorldEditor.java | 6 ++--- src/main/java/de/diddiz/util/BukkitUtils.java | 10 ++++----- .../java/de/diddiz/util/MaterialName.java | 14 ++++++------ src/main/java/de/diddiz/util/Utils.java | 9 ++++++++ src/main/resources/plugin.yml | 2 +- 9 files changed, 51 insertions(+), 23 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/ChestAccess.java b/src/main/java/de/diddiz/LogBlock/ChestAccess.java index a59080b..f31b735 100644 --- a/src/main/java/de/diddiz/LogBlock/ChestAccess.java +++ b/src/main/java/de/diddiz/LogBlock/ChestAccess.java @@ -2,10 +2,9 @@ package de.diddiz.LogBlock; public class ChestAccess { - final short itemType, itemAmount; - final byte itemData; + final short itemType, itemAmount, itemData; - public ChestAccess(short itemType, short itemAmount, byte itemData) { + public ChestAccess(short itemType, short itemAmount, short itemData) { this.itemType = itemType; this.itemAmount = itemAmount; this.itemData = itemData >= 0 ? itemData : 0; diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index 16cbf56..a7ecb43 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -607,7 +607,7 @@ public class CommandsHandler implements CommandExecutor final WorldEditor editor = new WorldEditor(logblock, params.world); while (rs.next()) - editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("type"), rs.getByte("data"), rs.getString("signtext"), rs.getShort("itemtype"), rs.getShort("itemamount"), rs.getByte("itemdata")); + editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("type"), rs.getByte("data"), rs.getString("signtext"), rs.getShort("itemtype"), rs.getShort("itemamount"), rs.getShort("itemdata")); final int changes = editor.getSize(); if (changes > 10000) { editor.setSender(sender); diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 4aa7558..5247b89 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -122,7 +122,7 @@ public class Consumer extends TimerTask * @param container * The respective container. Must be an instance of an InventoryHolder. */ - public void queueChestAccess(String playerName, BlockState container, short itemType, short itemAmount, byte itemData) { + public void queueChestAccess(String playerName, BlockState container, short itemType, short itemAmount, short itemData) { if (!(container instanceof InventoryHolder)) return; queueChestAccess(playerName, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getTypeId(), itemType, itemAmount, itemData); @@ -132,7 +132,7 @@ public class Consumer extends TimerTask * @param type * Type id of the container. */ - public void queueChestAccess(String playerName, Location loc, int type, short itemType, short itemAmount, byte itemData) { + public void queueChestAccess(String playerName, Location loc, int type, short itemType, short itemAmount, short itemData) { queueBlock(playerName, loc, type, type, (byte)0, null, new ChestAccess(itemType, itemAmount, itemData)); } diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 7691715..195af4f 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -235,6 +235,26 @@ class Updater } config.set("version", "1.71"); } + if (config.getString("version").compareTo("1.72") < 0) { + getLogger().info("Updating tables to 1.72 ..."); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + for (final WorldConfig wcfg : getLoggedWorlds()) { + if (wcfg.isLogging(Logging.CHESTACCESS)) { + st.execute("ALTER TABLE `"+wcfg.table+"-chest` CHANGE itemdata itemdata SMALLINT UNSIGNED NOT NULL"); + getLogger().info("Table "+wcfg.table+"-chest modified"); + } + } + st.close(); + conn.close(); + } catch (final SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.72"); + } logblock.saveConfig(); return true; @@ -257,7 +277,7 @@ class Updater for (final WorldConfig wcfg : getLoggedWorlds()) { createTable(dbm, state, wcfg.table, "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced TINYINT UNSIGNED NOT NULL, type TINYINT UNSIGNED NOT NULL, data TINYINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))"); createTable(dbm, state, wcfg.table + "-sign", "(id INT UNSIGNED NOT NULL, signtext VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET utf8"); - createTable(dbm, state, wcfg.table + "-chest", "(id INT UNSIGNED NOT NULL, itemtype SMALLINT UNSIGNED NOT NULL, itemamount SMALLINT NOT NULL, itemdata TINYINT UNSIGNED NOT NULL, PRIMARY KEY (id))"); + createTable(dbm, state, wcfg.table + "-chest", "(id INT UNSIGNED NOT NULL, itemtype SMALLINT UNSIGNED NOT NULL, itemamount SMALLINT NOT NULL, itemdata SMALLINT UNSIGNED NOT NULL, PRIMARY KEY (id))"); if (wcfg.isLogging(Logging.KILL)) createTable(dbm, state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id))"); } diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 4654224..cecbfc4 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -71,7 +71,7 @@ public class WorldEditor implements Runnable this.sender = sender; } - public void queueEdit(int x, int y, int z, int replaced, int type, byte data, String signtext, short itemType, short itemAmount, byte itemData) { + public void queueEdit(int x, int y, int z, int replaced, int type, byte data, String signtext, short itemType, short itemAmount, short itemData) { edits.add(new Edit(0, new Location(world, x, y, z), null, replaced, type, data, signtext, new ChestAccess(itemType, itemAmount, itemData))); } @@ -165,11 +165,11 @@ public class WorldEditor implements Runnable } else if (ca != null && (type == 23 || type == 54 || type == 61 || type == 62)) { int leftover; try { - leftover = modifyContainer(state, new ItemStack(ca.itemType, -ca.itemAmount, (short)0, ca.itemData)); + leftover = modifyContainer(state, new ItemStack(ca.itemType, -ca.itemAmount, ca.itemData)); if (leftover > 0) for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) if (block.getRelative(face).getTypeId() == 54) - leftover = modifyContainer(block.getRelative(face).getState(), new ItemStack(ca.itemType, ca.itemAmount < 0 ? leftover : -leftover, (short)0, ca.itemData)); + leftover = modifyContainer(block.getRelative(face).getState(), new ItemStack(ca.itemType, ca.itemAmount < 0 ? leftover : -leftover, ca.itemData)); } catch (final Exception ex) { throw new WorldEditorException(ex.getMessage(), block.getLocation()); } diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index 59f45a7..c930cf4 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -242,7 +242,7 @@ public class BukkitUtils for (final ItemStack item : items) if (item != null) { final int type = item.getTypeId(); - final byte data = rawData(item); + final short data = rawData(item); boolean found = false; for (final ItemStack item2 : compressed) if (type == item2.getTypeId() && data == rawData(item2)) { @@ -251,7 +251,7 @@ public class BukkitUtils break; } if (!found) - compressed.add(new ItemStack(type, item.getAmount(), (short)0, data)); + compressed.add(new ItemStack(type, item.getAmount(), data)); } Collections.sort(compressed, new ItemStackComparator()); return compressed.toArray(new ItemStack[compressed.size()]); @@ -322,8 +322,8 @@ public class BukkitUtils } } - public static byte rawData(ItemStack item) { - return item.getType() != null ? item.getData() != null ? item.getData().getData() : 0 : 0; + public static short rawData(ItemStack item) { + return item.getType() != null ? item.getData() != null ? item.getDurability() : 0 : 0; } public static int saveSpawnHeight(Location loc) { @@ -381,7 +381,7 @@ public class BukkitUtils return -1; if (aType > bType) return 1; - final byte aData = rawData(a), bData = rawData(b); + final short aData = rawData(a), bData = rawData(b); if (aData < bData) return -1; if (aData > bData) diff --git a/src/main/java/de/diddiz/util/MaterialName.java b/src/main/java/de/diddiz/util/MaterialName.java index ca9c92f..4855316 100644 --- a/src/main/java/de/diddiz/util/MaterialName.java +++ b/src/main/java/de/diddiz/util/MaterialName.java @@ -1,7 +1,7 @@ package de.diddiz.util; -import static de.diddiz.util.Utils.isByte; import static de.diddiz.util.Utils.isInt; +import static de.diddiz.util.Utils.isShort; import static org.bukkit.Bukkit.getLogger; import java.io.File; import java.io.IOException; @@ -16,7 +16,7 @@ import org.bukkit.material.MaterialData; public class MaterialName { private static final Map materialNames = new HashMap(); - private static final Map> materialDataNames = new HashMap>(); + private static final Map> materialDataNames = new HashMap>(); static { // Add all known materials @@ -57,13 +57,13 @@ public class MaterialName if (cfg.isString(entry)) materialNames.put(Integer.valueOf(entry), cfg.getString(entry)); else if (cfg.isConfigurationSection(entry)) { - final Map dataNames = new HashMap(); + final Map dataNames = new HashMap(); materialDataNames.put(Integer.valueOf(entry), dataNames); final ConfigurationSection sec = cfg.getConfigurationSection(entry); for (final String data : sec.getKeys(false)) - if (isByte(data)) { + if (isShort(data)) { if (sec.isString(data)) - dataNames.put(Byte.valueOf(data), sec.getString(data)); + dataNames.put(Short.valueOf(data), sec.getString(data)); else getLogger().warning("Parsing materials.yml: '" + data + "' is not a string."); } else @@ -84,8 +84,8 @@ public class MaterialName /** * @return Name of the material regarding it's data, or if it's unknown, the basic name. */ - public static String materialName(int type, byte data) { - final Map dataNames = materialDataNames.get(type); + public static String materialName(int type, short data) { + final Map dataNames = materialDataNames.get(type); if (dataNames != null) if (dataNames.containsKey(data)) return dataNames.get(data); diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index 167dec7..7959b63 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -19,6 +19,15 @@ public class Utils return false; } + public static boolean isShort(String str) { + try { + Short.parseShort(str); + return true; + } catch (final NumberFormatException ex) { + } + return false; + } + public static boolean isByte(String str) { try { Byte.parseByte(str); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index ce1095d..fea01ee 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: ${project.name} -version: '1.71' +version: '1.72' author: DiddiZ authors: [md_5, ammar2] website: http://dev.bukkit.org/server-mods/logblock/ From 2ff6da183b9f8cb66d968070f3bf11ea43421059 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Wed, 4 Dec 2013 11:34:25 +0000 Subject: [PATCH 19/50] Use modern column widths if upgrading from very old version --- src/main/java/de/diddiz/LogBlock/Updater.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 7691715..c967aa3 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -168,7 +168,7 @@ class Updater final Statement st = conn.createStatement(); for (final WorldConfig wcfg : getLoggedWorlds()) if (wcfg.isLogging(Logging.KILL)) - st.execute("ALTER TABLE `" + wcfg.table + "-kills` ADD (x SMALLINT NOT NULL DEFAULT 0, y TINYINT UNSIGNED NOT NULL DEFAULT 0, z SMALLINT NOT NULL DEFAULT 0)"); + st.execute("ALTER TABLE `" + wcfg.table + "-kills` ADD (x MEDIUMINT NOT NULL DEFAULT 0, y SMALLINT NOT NULL DEFAULT 0, z MEDIUMINT NOT NULL DEFAULT 0)"); st.close(); conn.close(); } catch (final SQLException ex) { From 38e1c6059f0e646bfcc62a284b7ca473731cd985 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Wed, 4 Dec 2013 11:52:00 +0000 Subject: [PATCH 20/50] NBT (and Java) shorts are signed --- src/main/java/de/diddiz/LogBlock/Updater.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 195af4f..4c0fb2d 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -243,7 +243,7 @@ class Updater final Statement st = conn.createStatement(); for (final WorldConfig wcfg : getLoggedWorlds()) { if (wcfg.isLogging(Logging.CHESTACCESS)) { - st.execute("ALTER TABLE `"+wcfg.table+"-chest` CHANGE itemdata itemdata SMALLINT UNSIGNED NOT NULL"); + st.execute("ALTER TABLE `"+wcfg.table+"-chest` CHANGE itemdata itemdata SMALLINT NOT NULL"); getLogger().info("Table "+wcfg.table+"-chest modified"); } } @@ -277,7 +277,7 @@ class Updater for (final WorldConfig wcfg : getLoggedWorlds()) { createTable(dbm, state, wcfg.table, "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced TINYINT UNSIGNED NOT NULL, type TINYINT UNSIGNED NOT NULL, data TINYINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT UNSIGNED NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))"); createTable(dbm, state, wcfg.table + "-sign", "(id INT UNSIGNED NOT NULL, signtext VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET utf8"); - createTable(dbm, state, wcfg.table + "-chest", "(id INT UNSIGNED NOT NULL, itemtype SMALLINT UNSIGNED NOT NULL, itemamount SMALLINT NOT NULL, itemdata SMALLINT UNSIGNED NOT NULL, PRIMARY KEY (id))"); + createTable(dbm, state, wcfg.table + "-chest", "(id INT UNSIGNED NOT NULL, itemtype SMALLINT UNSIGNED NOT NULL, itemamount SMALLINT NOT NULL, itemdata SMALLINT NOT NULL, PRIMARY KEY (id))"); if (wcfg.isLogging(Logging.KILL)) createTable(dbm, state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id))"); } From 28b4c2f60cb710e930c391457495b5de14f37129 Mon Sep 17 00:00:00 2001 From: md-5 Date: Thu, 5 Dec 2013 13:26:03 +1100 Subject: [PATCH 21/50] Bump to release 1.80 --- src/main/resources/plugin.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index ce1095d..268dd3f 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: ${project.name} -version: '1.71' +version: '1.80' author: DiddiZ -authors: [md_5, ammar2] +authors: [md_5, ammar2, frymaster] website: http://dev.bukkit.org/server-mods/logblock/ main: de.diddiz.LogBlock.LogBlock description: ${project.description} From 0d5607be43511008c48c2ed79f28e6c957394679 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Thu, 5 Dec 2013 08:42:20 +0000 Subject: [PATCH 22/50] Update PR for new version number --- src/main/java/de/diddiz/LogBlock/Updater.java | 6 +++--- src/main/resources/plugin.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 1efe43f..6c334dc 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -235,8 +235,8 @@ class Updater } config.set("version", "1.71"); } - if (config.getString("version").compareTo("1.72") < 0) { - getLogger().info("Updating tables to 1.72 ..."); + if (config.getString("version").compareTo("1.81") < 0) { + getLogger().info("Updating tables to 1.81 ..."); final Connection conn = logblock.getConnection(); try { conn.setAutoCommit(true); @@ -253,7 +253,7 @@ class Updater Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); return false; } - config.set("version", "1.72"); + config.set("version", "1.81"); } logblock.saveConfig(); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 268dd3f..dce6cb3 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: ${project.name} -version: '1.80' +version: '1.81' author: DiddiZ authors: [md_5, ammar2, frymaster] website: http://dev.bukkit.org/server-mods/logblock/ From 0c5fbd7fffeb7743a92757156641aeab7527573a Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Mon, 9 Dec 2013 09:32:47 +0000 Subject: [PATCH 23/50] Replace overlooked getByte calls with getShort for itemdata. Fixes #508 --- src/main/java/de/diddiz/LogBlock/BlockChange.java | 2 +- src/main/java/de/diddiz/LogBlock/CommandsHandler.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 0af5ea6..ae5ce7b 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -41,7 +41,7 @@ public class BlockChange implements LookupCacheElement type = p.needType ? rs.getInt("type") : 0; data = p.needData ? rs.getByte("data") : (byte)0; signtext = p.needSignText ? rs.getString("signtext") : null; - ca = p.needChestAccess && rs.getShort("itemtype") != 0 && rs.getShort("itemamount") != 0 ? new ChestAccess(rs.getShort("itemtype"), rs.getShort("itemamount"), rs.getByte("itemdata")) : null; + ca = p.needChestAccess && rs.getShort("itemtype") != 0 && rs.getShort("itemamount") != 0 ? new ChestAccess(rs.getShort("itemtype"), rs.getShort("itemamount"), rs.getShort("itemdata")) : null; } @Override diff --git a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java index a7ecb43..c6636c3 100755 --- a/src/main/java/de/diddiz/LogBlock/CommandsHandler.java +++ b/src/main/java/de/diddiz/LogBlock/CommandsHandler.java @@ -672,7 +672,7 @@ public class CommandsHandler implements CommandExecutor sender.sendMessage(ChatColor.DARK_AQUA + "Searching " + params.getTitle() + ":"); final WorldEditor editor = new WorldEditor(logblock, params.world); while (rs.next()) - editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("replaced"), rs.getByte("data"), rs.getString("signtext"), rs.getShort("itemtype"), (short)-rs.getShort("itemamount"), rs.getByte("itemdata")); + editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("replaced"), rs.getByte("data"), rs.getString("signtext"), rs.getShort("itemtype"), (short)-rs.getShort("itemamount"), rs.getShort("itemdata")); final int changes = editor.getSize(); if (!params.silent) sender.sendMessage(ChatColor.GREEN.toString() + changes + " blocks found."); From 3cffeccedbc151330897f62bfe17956ff8b12e16 Mon Sep 17 00:00:00 2001 From: Dark Arc Date: Fri, 6 Dec 2013 01:19:04 -0500 Subject: [PATCH 24/50] Updated Smart Logging for 1.7.2 and resolved a bug with door logging --- pom.xml | 2 +- src/main/java/de/diddiz/util/BukkitUtils.java | 18 ++++++++- src/main/java/de/diddiz/util/LoggingUtil.java | 37 ++++++++++++++++--- 3 files changed, 48 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index 0e620a1..53666b9 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ org.bukkit bukkit - 1.6.1-R0.1-SNAPSHOT + 1.7.2-R0.1-SNAPSHOT ${project.groupId} diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index c930cf4..7c3a717 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -60,7 +60,7 @@ public class BukkitUtils relativeBreakable.add(Material.COCOA); // Blocks that break when they are on top of a block - relativeTopBreakable = new HashSet(32); + relativeTopBreakable = new HashSet(33); relativeTopBreakable.add(Material.SAPLING); relativeTopBreakable.add(Material.LONG_GRASS); relativeTopBreakable.add(Material.DEAD_BUSH); @@ -91,8 +91,9 @@ public class BukkitUtils relativeTopBreakable.add(Material.REDSTONE_COMPARATOR_ON); relativeTopBreakable.add(Material.REDSTONE_COMPARATOR_OFF); relativeTopBreakable.add(Material.WOODEN_DOOR); - relativeTopBreakable.add(Material.IRON_DOOR); + relativeTopBreakable.add(Material.IRON_DOOR_BLOCK); relativeTopBreakable.add(Material.CARPET); + relativeTopBreakable.add(Material.DOUBLE_PLANT); // Blocks that fall relativeTopFallables = new HashSet(4); @@ -179,6 +180,19 @@ public class BukkitUtils return blocks; } + public static boolean isTop(Material mat, byte data) { + + switch (mat) { + case DOUBLE_PLANT: + return data > 5; + case IRON_DOOR_BLOCK: + case WOODEN_DOOR: + return data == 8 || data == 9; + default: + return false; + } + } + public static int getInventoryHolderType(InventoryHolder holder) { if (holder instanceof DoubleChest) { return ((DoubleChest)holder).getLocation().getBlock().getTypeId(); diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index 5b905bb..be6c0c3 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -73,18 +73,30 @@ public class LoggingUtil { if (BukkitUtils.getRelativeTopBreakabls().contains(checkBlock.getType())) { if (wcfg.isLogging(Logging.SIGNTEXT) && checkBlock.getType() == Material.SIGN_POST) { consumer.queueSignBreak(playerName, (Sign) checkBlock.getState()); - } else if (checkBlock.getType() == Material.IRON_DOOR || checkBlock.getType() == Material.WOOD_DOOR) { + } else if (checkBlock.getType() == Material.IRON_DOOR_BLOCK || checkBlock.getType() == Material.WOODEN_DOOR) { Block doorBlock = checkBlock; // If the doorBlock is the top half a door the player simply punched a door // this will be handled later. - if (doorBlock.getData() != 8 && doorBlock.getData() != 9) { + if (!BukkitUtils.isTop(doorBlock.getType(), doorBlock.getData())) { doorBlock = doorBlock.getRelative(BlockFace.UP); // Fall back check just in case the top half wasn't a door - if (doorBlock.getType() == Material.IRON_DOOR || doorBlock.getType() == Material.WOOD_DOOR) { + if (doorBlock.getType() == Material.IRON_DOOR_BLOCK || doorBlock.getType() == Material.WOODEN_DOOR) { consumer.queueBlockBreak(playerName, doorBlock.getState()); } consumer.queueBlockBreak(playerName, checkBlock.getState()); } + } else if (checkBlock.getType() == Material.DOUBLE_PLANT) { + Block plantBlock = checkBlock; + // If the plantBlock is the top half of a double plant the player simply + // punched the plant this will be handled later. + if (!BukkitUtils.isTop(plantBlock.getType(), plantBlock.getData())) { + plantBlock = plantBlock.getRelative(BlockFace.UP); + // Fall back check just in case the top half wasn't a plant + if (plantBlock.getType() == Material.DOUBLE_PLANT) { + consumer.queueBlockBreak(playerName, plantBlock.getState()); + } + consumer.queueBlockBreak(playerName, checkBlock.getState()); + } } else { consumer.queueBlockBreak(playerName, checkBlock.getState()); } @@ -156,19 +168,32 @@ public class LoggingUtil { } // Special door check - if (origin.getType() == Material.IRON_DOOR || origin.getType() == Material.WOOD_DOOR) { + if (origin.getType() == Material.IRON_DOOR_BLOCK || origin.getType() == Material.WOODEN_DOOR) { Block doorBlock = origin; // Up or down? - if (origin.getData() != 8 && origin.getData() != 9) { + if (!BukkitUtils.isTop(doorBlock.getType(), doorBlock.getData())) { doorBlock = doorBlock.getRelative(BlockFace.UP); } else { doorBlock = doorBlock.getRelative(BlockFace.DOWN); } - if (doorBlock.getType() == Material.IRON_DOOR || doorBlock.getType() == Material.WOOD_DOOR) { + if (doorBlock.getType() == Material.IRON_DOOR_BLOCK || doorBlock.getType() == Material.WOODEN_DOOR) { consumer.queueBlockBreak(playerName, doorBlock.getState()); } + } else if (origin.getType() == Material.DOUBLE_PLANT) { // Special double plant check + Block plantBlock = origin; + + // Up or down? + if (!BukkitUtils.isTop(origin.getType(), origin.getData())) { + plantBlock = plantBlock.getRelative(BlockFace.UP); + } else { + plantBlock = plantBlock.getRelative(BlockFace.DOWN); + } + + if (plantBlock.getType() == Material.DOUBLE_PLANT) { + consumer.queueBlockBreak(playerName, plantBlock.getState()); + } } // Do this down here so that the block is added after blocks sitting on it From 4519c79e6886a40106332589f4ff893569474b09 Mon Sep 17 00:00:00 2001 From: bm01 Date: Tue, 10 Dec 2013 20:06:51 +0100 Subject: [PATCH 25/50] Made "trapped chest" content rollbackable --- .../java/de/diddiz/LogBlock/WorldEditor.java | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index cecbfc4..9ed5f87 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -162,21 +162,24 @@ public class WorldEditor implements Runnable if (type == 0) { if (!block.setTypeId(0)) throw new WorldEditorException(block.getTypeId(), 0, block.getLocation()); - } else if (ca != null && (type == 23 || type == 54 || type == 61 || type == 62)) { - int leftover; - try { - leftover = modifyContainer(state, new ItemStack(ca.itemType, -ca.itemAmount, ca.itemData)); - if (leftover > 0) - for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) - if (block.getRelative(face).getTypeId() == 54) - leftover = modifyContainer(block.getRelative(face).getState(), new ItemStack(ca.itemType, ca.itemAmount < 0 ? leftover : -leftover, ca.itemData)); - } catch (final Exception ex) { - throw new WorldEditorException(ex.getMessage(), block.getLocation()); + } else if (ca != null ) { + boolean chest = (type == 54 || type == 146); + if (chest || type == 23 || type == 61 || type == 62) { + int leftover; + try { + leftover = modifyContainer(state, new ItemStack(ca.itemType, -ca.itemAmount, ca.itemData)); + if (leftover > 0 && chest) + for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) + if (block.getRelative(face).getTypeId() == type) + leftover = modifyContainer(block.getRelative(face).getState(), new ItemStack(ca.itemType, ca.itemAmount < 0 ? leftover : -leftover, ca.itemData)); + } catch (final Exception ex) { + throw new WorldEditorException(ex.getMessage(), block.getLocation()); + } + if (!state.update()) + throw new WorldEditorException("Failed to update inventory of " + materialName(block.getTypeId()), block.getLocation()); + if (leftover > 0 && ca.itemAmount < 0) + throw new WorldEditorException("Not enough space left in " + materialName(block.getTypeId()), block.getLocation()); } - if (!state.update()) - throw new WorldEditorException("Failed to update inventory of " + materialName(block.getTypeId()), block.getLocation()); - if (leftover > 0 && ca.itemAmount < 0) - throw new WorldEditorException("Not enough space left in " + materialName(block.getTypeId()), block.getLocation()); } else return PerformResult.NO_ACTION; return PerformResult.SUCCESS; From bbe798987833c8e6f56f5b2a1be041a2d4697d39 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Mon, 16 Dec 2013 14:46:15 +0000 Subject: [PATCH 26/50] Improvements to checks for inventory blocks and double inventory blocks These commits replace all checks of the form type == someInventoryBlockId || type = anotherOne with a call to getContainerBlocks().contains(Material.getMaterial(type)) This was done by searching the code for 54 which is the chest ID. Remaining explicit mentions of id 54 are in regards to special-casing for double chests - the code there has been expanded to also consider id 146, the trapped chest. I didn't think it worth making a collection for double-block inventories, but if more are added it should be considered - looking forward, this might be necessary when the mod API comes in, assuming we have a way of figuring out what double inventories are anyway. This fixes many blocks not having inventories logged when destroyed due to explosions, or not being rollbackable, and tools not querying both sides of double trapped chests. Rolling back e.g. a furnace is glitchy - the fuel, raw material and product do not get placed in the correct slots. - Update list of container blocks - Make tool treat trapped chests as potential double chests - Replace explicit id checks with a call to getContainerBlocks() --- src/main/java/de/diddiz/LogBlock/WorldEditor.java | 10 ++++++---- .../de/diddiz/LogBlock/listeners/ExplosionLogging.java | 4 +++- .../de/diddiz/LogBlock/listeners/ToolListener.java | 4 ++-- src/main/java/de/diddiz/util/BukkitUtils.java | 1 + 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 9ed5f87..4c52f1c 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -10,6 +10,7 @@ import org.bukkit.block.Sign; import org.bukkit.command.CommandSender; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import org.bukkit.Material; import org.bukkit.material.Bed; import org.bukkit.material.PistonBaseMaterial; import org.bukkit.material.PistonExtensionMaterial; @@ -26,6 +27,7 @@ import java.util.logging.Level; import static de.diddiz.LogBlock.config.Config.dontRollback; import static de.diddiz.LogBlock.config.Config.replaceAnyway; import static de.diddiz.util.BukkitUtils.equalTypes; +import static de.diddiz.util.BukkitUtils.getContainerBlocks; import static de.diddiz.util.BukkitUtils.modifyContainer; import static de.diddiz.util.MaterialName.materialName; import static org.bukkit.Bukkit.getLogger; @@ -162,13 +164,13 @@ public class WorldEditor implements Runnable if (type == 0) { if (!block.setTypeId(0)) throw new WorldEditorException(block.getTypeId(), 0, block.getLocation()); - } else if (ca != null ) { - boolean chest = (type == 54 || type == 146); - if (chest || type == 23 || type == 61 || type == 62) { + } else if (ca != null) { + if (getContainerBlocks().contains(Material.getMaterial(type))) { int leftover; try { leftover = modifyContainer(state, new ItemStack(ca.itemType, -ca.itemAmount, ca.itemData)); - if (leftover > 0 && chest) + // Special-case blocks which might be double chests + if (leftover > 0 && (type == 54 || type == 146)) for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) if (block.getRelative(face).getTypeId() == type) leftover = modifyContainer(block.getRelative(face).getState(), new ItemStack(ca.itemType, ca.itemAmount < 0 ? leftover : -leftover, ca.itemData)); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index f16f8ef..f663b32 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -18,9 +18,11 @@ import org.bukkit.entity.WitherSkull; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.Material; import static de.diddiz.LogBlock.config.Config.getWorldConfig; import static de.diddiz.LogBlock.config.Config.logCreeperExplosionsAsPlayerWhoTriggeredThese; +import static de.diddiz.util.BukkitUtils.getContainerBlocks; public class ExplosionLogging extends LoggingListener { @@ -90,7 +92,7 @@ public class ExplosionLogging extends LoggingListener final int type = block.getTypeId(); if (wcfg.isLogging(Logging.SIGNTEXT) & (type == 63 || type == 68)) consumer.queueSignBreak(name, (Sign)block.getState()); - else if (wcfg.isLogging(Logging.CHESTACCESS) && (type == 23 || type == 54 || type == 61)) + else if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(Material.getMaterial(type)))) consumer.queueContainerBreak(name, block.getState()); else consumer.queueBlockBreak(name, block.getState()); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java index fd267f1..77751a8 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java @@ -60,12 +60,12 @@ public class ToolListener implements Listener params.sel = null; if (behavior == ToolBehavior.BLOCK) params.setLocation(block.getRelative(event.getBlockFace()).getLocation()); - else if (block.getTypeId() != 54 || tool.params.radius != 0) + else if ((block.getTypeId() != 54 && block.getTypeId() != 146) || tool.params.radius != 0) params.setLocation(block.getLocation()); else { if (logblock.getServer().getPluginManager().isPluginEnabled("WorldEdit")) { for (final BlockFace face : new BlockFace[]{BlockFace.NORTH, BlockFace.SOUTH, BlockFace.EAST, BlockFace.WEST}) { - if (block.getRelative(face).getTypeId() == 54) { + if (block.getRelative(face).getTypeId() == block.getTypeId()) { params.setSelection(RegionContainer.fromCorners(event.getPlayer().getWorld(), block.getLocation(), block.getRelative(face).getLocation())); } diff --git a/src/main/java/de/diddiz/util/BukkitUtils.java b/src/main/java/de/diddiz/util/BukkitUtils.java index c930cf4..0159581 100644 --- a/src/main/java/de/diddiz/util/BukkitUtils.java +++ b/src/main/java/de/diddiz/util/BukkitUtils.java @@ -153,6 +153,7 @@ public class BukkitUtils containerBlocks.add(Material.HOPPER); containerBlocks.add(Material.BREWING_STAND); containerBlocks.add(Material.FURNACE); + containerBlocks.add(Material.BURNING_FURNACE); containerBlocks.add(Material.BEACON); // Doesn't actually have a block inventory // containerBlocks.add(Material.ENDER_CHEST); From 05fe4f21448e0ecfbf75eca362223fe8c58df86e Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Wed, 15 Jan 2014 14:02:36 +0000 Subject: [PATCH 27/50] Move null check in tool code one level out. This means it will guard against trying to use worldedit for querying double chests when worldedit is not loaded. Fixes #511 Long-term, perhaps rather than using a worldedit object directly, we should use our own interface which supports similar methods and have two implementations, one which uses a worldedit selection and one which takes two corner coordinates for use in double chests. That might also allow for custom queries along those lines. --- .../java/de/diddiz/LogBlock/listeners/ToolListener.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java index 77751a8..1a7a622 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ToolListener.java @@ -70,9 +70,9 @@ public class ToolListener implements Listener block.getLocation(), block.getRelative(face).getLocation())); } } - if (params.sel == null) { - params.setLocation(block.getLocation()); - } + } + if (params.sel == null) { + params.setLocation(block.getLocation()); } } try { From fa1e1b777a9da062d10d7c3c1906520e4d39eba8 Mon Sep 17 00:00:00 2001 From: Dark Arc Date: Thu, 3 Apr 2014 23:22:26 -0400 Subject: [PATCH 28/50] Updated for WorldEdit 6.0 --- pom.xml | 4 +- .../java/de/diddiz/LogBlock/LogBlock.java | 4 +- .../LogBlock/listeners/ExplosionLogging.java | 3 +- .../diddiz/worldedit/LogBlockEditSession.java | 78 ---------------- .../worldedit/LogBlockEditSessionFactory.java | 39 -------- .../worldedit/WorldEditLoggingHook.java | 89 +++++++++++++++++++ 6 files changed, 95 insertions(+), 122 deletions(-) delete mode 100644 src/main/java/de/diddiz/worldedit/LogBlockEditSession.java delete mode 100644 src/main/java/de/diddiz/worldedit/LogBlockEditSessionFactory.java create mode 100644 src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java diff --git a/pom.xml b/pom.xml index 53666b9..f204b4f 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ org.bukkit bukkit - 1.7.2-R0.1-SNAPSHOT + 1.7.5-R0.1-SNAPSHOT ${project.groupId} @@ -54,7 +54,7 @@ com.sk89q worldedit - 5.5 + 6.0.0-SNAPSHOT diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 86df1b0..da3a40e 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -24,7 +24,7 @@ import de.diddiz.LogBlock.listeners.StructureGrowLogging; import de.diddiz.LogBlock.listeners.ToolListener; import de.diddiz.LogBlock.listeners.WitherLogging; import de.diddiz.util.MySQLConnectionPool; -import de.diddiz.worldedit.LogBlockEditSessionFactory; +import de.diddiz.worldedit.WorldEditLoggingHook; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -110,7 +110,7 @@ public class LogBlock extends JavaPlugin if (noDb) return; if (pm.getPlugin("WorldEdit") != null) { - LogBlockEditSessionFactory.initialize(this); + new WorldEditLoggingHook(this).hook(); } commandsHandler = new CommandsHandler(this); getCommand("lb").setExecutor(commandsHandler); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index f663b32..52c2267 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -19,6 +19,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.Material; +import org.bukkit.projectiles.ProjectileSource; import static de.diddiz.LogBlock.config.Config.getWorldConfig; import static de.diddiz.LogBlock.config.Config.logCreeperExplosionsAsPlayerWhoTriggeredThese; @@ -57,7 +58,7 @@ public class ExplosionLogging extends LoggingListener name = "Creeper"; } else if (source instanceof Fireball) { Fireball fireball = (Fireball) source; - Entity shooter = fireball.getShooter(); + ProjectileSource shooter = fireball.getShooter(); if (shooter == null) { return; } diff --git a/src/main/java/de/diddiz/worldedit/LogBlockEditSession.java b/src/main/java/de/diddiz/worldedit/LogBlockEditSession.java deleted file mode 100644 index f87c786..0000000 --- a/src/main/java/de/diddiz/worldedit/LogBlockEditSession.java +++ /dev/null @@ -1,78 +0,0 @@ -package de.diddiz.worldedit; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.bags.BlockBag; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.bukkit.BukkitWorld; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import de.diddiz.LogBlock.config.Config; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.BlockState; -import org.bukkit.block.Sign; - -public class LogBlockEditSession extends EditSession { - - private LocalPlayer player; - private LogBlock plugin; - - /** - * {@inheritDoc} - */ - public LogBlockEditSession(LocalWorld world, int maxBlocks, LocalPlayer player, LogBlock lb) { - super(world, maxBlocks); - this.player = player; - this.plugin = lb; - } - - /** - * {@inheritDoc} - */ - public LogBlockEditSession(LocalWorld world, int maxBlocks, BlockBag blockBag, LocalPlayer player, LogBlock lb) { - super(world, maxBlocks, blockBag); - this.player = player; - this.plugin = lb; - } - - @Override - public boolean rawSetBlock(Vector pt, BaseBlock block) { - if (!(player.getWorld() instanceof BukkitWorld) || !(Config.isLogging(player.getWorld().getName(), Logging.WORLDEDIT))) { - return super.rawSetBlock(pt, block); - } - - int typeBefore = ((BukkitWorld) player.getWorld()).getWorld().getBlockTypeIdAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - byte dataBefore = ((BukkitWorld) player.getWorld()).getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getData(); - // If we're dealing with a sign, store the block state to read the text off - BlockState stateBefore = null; - if (typeBefore == Material.SIGN_POST.getId() || typeBefore == Material.SIGN.getId()) { - stateBefore = ((BukkitWorld) player.getWorld()).getWorld().getBlockAt(pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()).getState(); - } - boolean success = super.rawSetBlock(pt, block); - if (success) { - Location location = new Location(((BukkitWorld) player.getWorld()).getWorld(), pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - - // Check to see if we've broken a sign - if (Config.isLogging(location.getWorld().getName(), Logging.SIGNTEXT) && (typeBefore == Material.SIGN_POST.getId() || typeBefore == Material.SIGN.getId())) { - plugin.getConsumer().queueSignBreak(player.getName(), (Sign) stateBefore); - if (block.getType() != Material.AIR.getId()) { - plugin.getConsumer().queueBlockPlace(player.getName(), location, block.getType(), (byte) block.getData()); - } - } else { - if (dataBefore != 0) { - plugin.getConsumer().queueBlockBreak(player.getName(), location, typeBefore, dataBefore); - if (block.getType() != Material.AIR.getId()) { - plugin.getConsumer().queueBlockPlace(player.getName(), location, block.getType(), (byte) block.getData()); - } - } else { - plugin.getConsumer().queueBlock(player.getName(), location, typeBefore, block.getType(), (byte) block.getData()); - } - } - } - return success; - } - -} diff --git a/src/main/java/de/diddiz/worldedit/LogBlockEditSessionFactory.java b/src/main/java/de/diddiz/worldedit/LogBlockEditSessionFactory.java deleted file mode 100644 index 50bf4b9..0000000 --- a/src/main/java/de/diddiz/worldedit/LogBlockEditSessionFactory.java +++ /dev/null @@ -1,39 +0,0 @@ -package de.diddiz.worldedit; - -import com.sk89q.worldedit.EditSession; -import com.sk89q.worldedit.EditSessionFactory; -import com.sk89q.worldedit.LocalPlayer; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.bags.BlockBag; -import de.diddiz.LogBlock.LogBlock; - -public class LogBlockEditSessionFactory extends EditSessionFactory { - - private LogBlock plugin; - - public LogBlockEditSessionFactory(LogBlock lb) { - this.plugin = lb; - } - - @Override - public EditSession getEditSession(LocalWorld world, int maxBlocks, LocalPlayer player) { - return new LogBlockEditSession(world, maxBlocks, player, plugin); - } - - @Override - public EditSession getEditSession(LocalWorld world, int maxBlocks, BlockBag blockBag, LocalPlayer player) { - return new LogBlockEditSession(world, maxBlocks, blockBag, player, plugin); - } - - public static void initialize(LogBlock logBlock) { - try { - // Check to see if the world edit version is compatible - Class.forName("com.sk89q.worldedit.EditSessionFactory").getDeclaredMethod("getEditSession", LocalWorld.class, int.class, BlockBag.class, LocalPlayer.class); - WorldEdit.getInstance().setEditSessionFactory(new LogBlockEditSessionFactory(logBlock)); - } catch (Throwable ignored) { - - } - } - -} diff --git a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java new file mode 100644 index 0000000..ed3ab74 --- /dev/null +++ b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java @@ -0,0 +1,89 @@ +package de.diddiz.worldedit; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.event.extent.EditSessionEvent; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.logging.AbstractLoggingExtent; +import com.sk89q.worldedit.util.eventbus.Subscribe; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.Config; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.Sign; + +public class WorldEditLoggingHook { + + private LogBlock plugin; + + public WorldEditLoggingHook(LogBlock plugin) { + this.plugin = plugin; + } + + public void hook() { + WorldEdit.getInstance().getEventBus().register(new Object() { + @Subscribe + public void wrapForLogging(final EditSessionEvent event) { + final Actor actor = event.getActor(); + if (actor == null || !(actor instanceof Player)) return; + + // Check to ensure the world should be logged + String worldName = event.getWorld().getName(); + // If config becomes reloadable, this check should be moved + if (!(Config.isLogging(worldName, Logging.WORLDEDIT))) { + return; + } + + final org.bukkit.World bukkitWorld = Bukkit.getWorld(worldName); + if (bukkitWorld == null) { + return; + } + + event.setExtent(new AbstractLoggingExtent(event.getExtent()) { + @Override + protected void onBlockChange(Vector pt, BaseBlock block) { + + if (event.getStage() != EditSession.Stage.BEFORE_CHANGE) { + return; + } + + Location location = new Location(bukkitWorld, pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); + + Block origin = location.getBlock(); + int typeBefore = origin.getTypeId(); + byte dataBefore = origin.getData(); + // If we're dealing with a sign, store the block state to read the text off + BlockState stateBefore = null; + if (typeBefore == Material.SIGN_POST.getId() || typeBefore == Material.SIGN.getId()) { + stateBefore = origin.getState(); + } + + // Check to see if we've broken a sign + if (Config.isLogging(location.getWorld().getName(), Logging.SIGNTEXT) && (typeBefore == Material.SIGN_POST.getId() || typeBefore == Material.SIGN.getId())) { + plugin.getConsumer().queueSignBreak(actor.getName(), (Sign) stateBefore); + if (block.getType() != Material.AIR.getId()) { + plugin.getConsumer().queueBlockPlace(actor.getName(), location, block.getType(), (byte) block.getData()); + } + } else { + if (dataBefore != 0) { + plugin.getConsumer().queueBlockBreak(actor.getName(), location, typeBefore, dataBefore); + if (block.getType() != Material.AIR.getId()) { + plugin.getConsumer().queueBlockPlace(actor.getName(), location, block.getType(), (byte) block.getData()); + } + } else { + plugin.getConsumer().queueBlock(actor.getName(), location, typeBefore, block.getType(), (byte) block.getData()); + } + } + } + }); + } + }); + } +} From 6e12d159b449096d0857f6e77fc50de3be2032af Mon Sep 17 00:00:00 2001 From: Ammar Askar Date: Sun, 8 Feb 2015 16:34:46 +0500 Subject: [PATCH 29/50] Verbose logging for PreparedStatements --- src/main/java/de/diddiz/LogBlock/Consumer.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 5247b89..2c37205 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -508,7 +508,15 @@ public class Consumer extends TimerTask ps.executeUpdate(); } } - // we intentionally do not catch SQLException, it is thrown to the caller + catch (final SQLException ex) { + if (ps1 != null) { + getLogger().log(Level.SEVERE, "[Consumer] Troublesome query: " + ps1.toString()); + } + if (ps != null) { + getLogger().log(Level.SEVERE, "[Consumer] Troublesome query: " + ps.toString()); + } + throw ex; + } finally { // individual try/catch here, though ugly, prevents resource leaks if( ps1 != null ) { From e3dc4309318e8292220619c1a7353bb2caa70e01 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Sat, 14 Feb 2015 13:52:06 +0000 Subject: [PATCH 30/50] Identify players by UUID and migrate existing databases to include this. Fixes #538, fixes #568 This creates a new column in the lb-players table called UUID. If this is in the form of a UUID, it's assumed to be a player. If not, it's assumed to be a server entity (zombie, sheep, or WaterFlow, LavaFlow etc.). LogBlock will set the UUID of entities to "log_" plus their name (i.e. log_zombie or log_sheep) To assist this is a new class Actor, which wraps a name/UUID pair, with constructors that will generate one from server entities, or SQL results. Every listener and every class in Consumer needed to be updated to deal with this As of yet, only the playername is displayed in results (although the queries do return UUID data). Similarly, you can only query by name (the database stores the last name they have logged in as). In addition, the WorldEdit hook has been disabled (is not compiled) since LB needs to be updated to use their new API, and the LB code hook has to extract UUID information for insertion. The UUID importer assumes any player with an onlinetime of 0 is a server-generated source, and set the UUID as above (log_sheep etc.). For everything else, it sends 100 names at a time to Mojang's name->UUID service, and records them if available. If no result is found, it records their UUID as noimport_theirname. As this is more likely than other updates to be interrupted mid-way, the importer is tolerant of e.g. the column already being added, and will resume where it left off. --- pom.xml | 3 + src/main/java/de/diddiz/LogBlock/Actor.java | 85 +++++++ .../java/de/diddiz/LogBlock/BlockChange.java | 11 +- .../java/de/diddiz/LogBlock/ChatMessage.java | 9 +- .../java/de/diddiz/LogBlock/Consumer.java | 237 ++++++++++-------- .../java/de/diddiz/LogBlock/LogBlock.java | 8 +- .../java/de/diddiz/LogBlock/QueryParams.java | 6 +- .../diddiz/LogBlock/SummedBlockChanges.java | 9 +- .../java/de/diddiz/LogBlock/SummedKills.java | 12 +- src/main/java/de/diddiz/LogBlock/Updater.java | 84 ++++++- .../java/de/diddiz/LogBlock/WorldEditor.java | 4 +- .../events/BlockChangePreLogEvent.java | 3 +- .../diddiz/LogBlock/events/PreLogEvent.java | 22 +- .../LogBlock/listeners/BlockBreakLogging.java | 17 +- .../LogBlock/listeners/BlockBurnLogging.java | 9 +- .../LogBlock/listeners/BlockPlaceLogging.java | 15 +- .../listeners/BlockSpreadLogging.java | 6 +- .../LogBlock/listeners/ChatLogging.java | 11 +- .../listeners/ChestAccessLogging.java | 3 +- .../listeners/CreatureInteractLogging.java | 8 +- .../LogBlock/listeners/EndermenLogging.java | 7 +- .../LogBlock/listeners/ExplosionLogging.java | 38 +-- .../LogBlock/listeners/FluidFlowLogging.java | 27 +- .../LogBlock/listeners/InteractLogging.java | 22 +- .../LogBlock/listeners/KillLogging.java | 11 +- .../listeners/LeavesDecayLogging.java | 9 +- .../listeners/LockedChestDecayLogging.java | 7 +- .../LogBlock/listeners/SignChangeLogging.java | 8 +- .../LogBlock/listeners/SnowFadeLogging.java | 7 +- .../LogBlock/listeners/SnowFormLogging.java | 17 +- .../listeners/StructureGrowLogging.java | 15 +- .../LogBlock/listeners/WitherLogging.java | 3 +- src/main/java/de/diddiz/util/LoggingUtil.java | 57 ++--- src/main/java/de/diddiz/util/UUIDFetcher.java | 79 ++++++ .../diddiz/worldedit/LogBlockEditSession.java | 2 +- src/main/resources/plugin.yml | 2 +- 36 files changed, 596 insertions(+), 277 deletions(-) create mode 100644 src/main/java/de/diddiz/LogBlock/Actor.java mode change 100755 => 100644 src/main/java/de/diddiz/LogBlock/SummedKills.java create mode 100644 src/main/java/de/diddiz/util/UUIDFetcher.java diff --git a/pom.xml b/pom.xml index 53666b9..d83cbb7 100644 --- a/pom.xml +++ b/pom.xml @@ -89,6 +89,9 @@ 1.6 1.6 + + **/de/diddiz/worldedit/*.java + diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java new file mode 100644 index 0000000..ab12a30 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -0,0 +1,85 @@ +package de.diddiz.LogBlock; + +import static de.diddiz.util.BukkitUtils.entityName; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; + +import java.sql.ResultSet; +import java.sql.SQLException; + +public class Actor { + + @Override + public int hashCode() { + int hash = 5; + hash = 79 * hash + (this.UUID != null ? this.UUID.hashCode() : 0); + return hash; + } + + @Override + public boolean equals(Object obj) { + if (obj == null) { + return false; + } + if (getClass() != obj.getClass()) { + return false; + } + final Actor other = (Actor) obj; + if ((this.UUID == null) ? (other.UUID != null) : !this.UUID.equals(other.UUID)) { + return false; + } + return true; + } + + final String name; + final String UUID; + + public Actor(String name, String UUID) { + this.name = name; + this.UUID = UUID; + + } + + public Actor(String name) { + this(name, generateUUID(name)); + } + + public Actor(ResultSet rs) throws SQLException { + this(rs.getString("playername"),rs.getString("UUID")); + } + + public String getName() { + return name; + } + + public String getUUID() { + return UUID; + } + + public static Actor actorFromEntity(Entity entity) { + if (entity instanceof Player) { + return new Actor(entityName(entity),entity.getUniqueId().toString()); + } else { + return new Actor(entityName(entity)); + } + } + + public static Actor actorFromEntity(EntityType entity) { + return new Actor(entity.getName()); + } + + public static boolean isValidUUID(String uuid) { + try { + java.util.UUID.fromString(uuid); + return true; + } catch (IllegalArgumentException e) { + return false; + } + } + + public static String generateUUID(String name) { + return "log_" + name; + + } +} diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index ae5ce7b..6e823a0 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -14,28 +14,31 @@ public class BlockChange implements LookupCacheElement { public final long id, date; public final Location loc; + public final Actor actor; public final String playerName; public final int replaced, type; public final byte data; public final String signtext; public final ChestAccess ca; - public BlockChange(long date, Location loc, String playerName, int replaced, int type, byte data, String signtext, ChestAccess ca) { + public BlockChange(long date, Location loc, Actor actor, int replaced, int type, byte data, String signtext, ChestAccess ca) { id = 0; this.date = date; this.loc = loc; - this.playerName = playerName; + this.actor = actor; this.replaced = replaced; this.type = type; this.data = data; this.signtext = signtext; this.ca = ca; + this.playerName = actor == null ? null : actor.getName(); } public BlockChange(ResultSet rs, QueryParams p) throws SQLException { id = p.needId ? rs.getInt("id") : 0; date = p.needDate ? rs.getTimestamp("date").getTime() : 0; loc = p.needCoords ? new Location(p.world, rs.getInt("x"), rs.getInt("y"), rs.getInt("z")) : null; + actor = p.needPlayer ? new Actor(rs) : null; playerName = p.needPlayer ? rs.getString("playername") : null; replaced = p.needType ? rs.getInt("replaced") : 0; type = p.needType ? rs.getInt("type") : 0; @@ -49,8 +52,8 @@ public class BlockChange implements LookupCacheElement final StringBuilder msg = new StringBuilder(); if (date > 0) msg.append(Config.formatter.format(date)).append(" "); - if (playerName != null) - msg.append(playerName).append(" "); + if (actor != null) + msg.append(actor.getName()).append(" "); if (signtext != null) { final String action = type == 0 ? "destroyed " : "created "; if (!signtext.contains("\0")) diff --git a/src/main/java/de/diddiz/LogBlock/ChatMessage.java b/src/main/java/de/diddiz/LogBlock/ChatMessage.java index 00272d5..a060317 100644 --- a/src/main/java/de/diddiz/LogBlock/ChatMessage.java +++ b/src/main/java/de/diddiz/LogBlock/ChatMessage.java @@ -8,17 +8,20 @@ public class ChatMessage implements LookupCacheElement { final long id, date; final String playerName, message; + final Actor player; - public ChatMessage(String playerName, String message) { + public ChatMessage(Actor player, String message) { id = 0; date = System.currentTimeMillis() / 1000; - this.playerName = playerName; + this.player = player; this.message = message; + this.playerName = player == null ? null : player.getName(); } public ChatMessage(ResultSet rs, QueryParams p) throws SQLException { id = p.needId ? rs.getInt("id") : 0; date = p.needDate ? rs.getTimestamp("date").getTime() : 0; + player = p.needPlayer ? new Actor(rs) : null; playerName = p.needPlayer ? rs.getString("playername") : null; message = p.needMessage ? rs.getString("message") : null; } @@ -30,6 +33,6 @@ public class ChatMessage implements LookupCacheElement @Override public String getMessage() { - return (playerName != null ? "<" + playerName + "> " : "") + (message != null ? message : ""); + return (player != null ? "<" + player.getName() + "> " : "") + (message != null ? message : ""); } } diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 5247b89..38fd7ce 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -29,9 +29,9 @@ import static org.bukkit.Bukkit.getLogger; public class Consumer extends TimerTask { private final Queue queue = new LinkedBlockingQueue(); - private final Set failedPlayers = new HashSet(); + private final Set failedPlayers = new HashSet(); private final LogBlock logblock; - private final Map playerIds = new HashMap(); + private final Map playerIds = new HashMap(); private final Lock lock = new ReentrantLock(); Consumer(LogBlock logblock) { @@ -45,8 +45,8 @@ public class Consumer extends TimerTask /** * Logs any block change. Don't try to combine broken and placed blocks. Queue two block changes or use the queueBLockReplace methods. */ - public void queueBlock(String playerName, Location loc, int typeBefore, int typeAfter, byte data) { - queueBlock(playerName, loc, typeBefore, typeAfter, data, null, null); + public void queueBlock(Actor actor, Location loc, int typeBefore, int typeAfter, byte data) { + queueBlock(actor, loc, typeBefore, typeAfter, data, null, null); } /** @@ -55,15 +55,15 @@ public class Consumer extends TimerTask * @param before * Blockstate of the block before actually being destroyed. */ - public void queueBlockBreak(String playerName, BlockState before) { - queueBlockBreak(playerName, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData()); + public void queueBlockBreak(Actor actor, BlockState before) { + queueBlockBreak(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData()); } /** * Logs a block break. The block type afterwards is assumed to be o (air). */ - public void queueBlockBreak(String playerName, Location loc, int typeBefore, byte dataBefore) { - queueBlock(playerName, loc, typeBefore, 0, dataBefore); + public void queueBlockBreak(Actor actor, Location loc, int typeBefore, byte dataBefore) { + queueBlock(actor, loc, typeBefore, 0, dataBefore); } /** @@ -72,15 +72,15 @@ public class Consumer extends TimerTask * @param after * Blockstate of the block after actually being placed. */ - public void queueBlockPlace(String playerName, BlockState after) { - queueBlockPlace(playerName, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), after.getBlock().getTypeId(), after.getBlock().getData()); + public void queueBlockPlace(Actor actor, BlockState after) { + queueBlockPlace(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), after.getBlock().getTypeId(), after.getBlock().getData()); } /** * Logs a block place. The block type before is assumed to be o (air). */ - public void queueBlockPlace(String playerName, Location loc, int type, byte data) { - queueBlock(playerName, loc, 0, type, data); + public void queueBlockPlace(Actor actor, Location loc, int type, byte data) { + queueBlock(actor, loc, 0, type, data); } /** @@ -89,32 +89,32 @@ public class Consumer extends TimerTask * @param after * Blockstate of the block after actually being placed. */ - public void queueBlockReplace(String playerName, BlockState before, BlockState after) { - queueBlockReplace(playerName, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData(), after.getTypeId(), after.getRawData()); + public void queueBlockReplace(Actor actor, BlockState before, BlockState after) { + queueBlockReplace(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData(), after.getTypeId(), after.getRawData()); } /** * @param before * Blockstate of the block before actually being destroyed. */ - public void queueBlockReplace(String playerName, BlockState before, int typeAfter, byte dataAfter) { - queueBlockReplace(playerName, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData(), typeAfter, dataAfter); + public void queueBlockReplace(Actor actor, BlockState before, int typeAfter, byte dataAfter) { + queueBlockReplace(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getTypeId(), before.getRawData(), typeAfter, dataAfter); } /** * @param after * Blockstate of the block after actually being placed. */ - public void queueBlockReplace(String playerName, int typeBefore, byte dataBefore, BlockState after) { - queueBlockReplace(playerName, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), typeBefore, dataBefore, after.getTypeId(), after.getRawData()); + public void queueBlockReplace(Actor actor, int typeBefore, byte dataBefore, BlockState after) { + queueBlockReplace(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), typeBefore, dataBefore, after.getTypeId(), after.getRawData()); } - public void queueBlockReplace(String playerName, Location loc, int typeBefore, byte dataBefore, int typeAfter, byte dataAfter) { + public void queueBlockReplace(Actor actor, Location loc, int typeBefore, byte dataBefore, int typeAfter, byte dataAfter) { if (dataBefore == 0 && (typeBefore != typeAfter)) - queueBlock(playerName, loc, typeBefore, typeAfter, dataAfter); + queueBlock(actor, loc, typeBefore, typeAfter, dataAfter); else { - queueBlockBreak(playerName, loc, typeBefore, dataBefore); - queueBlockPlace(playerName, loc, typeAfter, dataAfter); + queueBlockBreak(actor, loc, typeBefore, dataBefore); + queueBlockPlace(actor, loc, typeAfter, dataAfter); } } @@ -122,18 +122,18 @@ public class Consumer extends TimerTask * @param container * The respective container. Must be an instance of an InventoryHolder. */ - public void queueChestAccess(String playerName, BlockState container, short itemType, short itemAmount, short itemData) { + public void queueChestAccess(Actor actor, BlockState container, short itemType, short itemAmount, short itemData) { if (!(container instanceof InventoryHolder)) return; - queueChestAccess(playerName, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getTypeId(), itemType, itemAmount, itemData); + queueChestAccess(actor, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getTypeId(), itemType, itemAmount, itemData); } /** * @param type * Type id of the container. */ - public void queueChestAccess(String playerName, Location loc, int type, short itemType, short itemAmount, short itemData) { - queueBlock(playerName, loc, type, type, (byte)0, null, new ChestAccess(itemType, itemAmount, itemData)); + public void queueChestAccess(Actor actor, Location loc, int type, short itemType, short itemAmount, short itemData) { + queueBlock(actor, loc, type, type, (byte)0, null, new ChestAccess(itemType, itemAmount, itemData)); } /** @@ -142,20 +142,20 @@ public class Consumer extends TimerTask * @param container * Must be an instance of InventoryHolder */ - public void queueContainerBreak(String playerName, BlockState container) { + public void queueContainerBreak(Actor actor, BlockState container) { if (!(container instanceof InventoryHolder)) return; - queueContainerBreak(playerName, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getTypeId(), container.getRawData(), ((InventoryHolder)container).getInventory()); + queueContainerBreak(actor, new Location(container.getWorld(), container.getX(), container.getY(), container.getZ()), container.getTypeId(), container.getRawData(), ((InventoryHolder)container).getInventory()); } /** * Logs a container block break. The block type before is assumed to be o (air). All content is assumed to be taken. */ - public void queueContainerBreak(String playerName, Location loc, int type, byte data, Inventory inv) { + public void queueContainerBreak(Actor actor, Location loc, int type, byte data, Inventory inv) { final ItemStack[] items = compressInventory(inv.getContents()); for (final ItemStack item : items) - queueChestAccess(playerName, loc, type, (short)item.getTypeId(), (short)(item.getAmount() * -1), rawData(item)); - queueBlockBreak(playerName, loc, type, data); + queueChestAccess(actor, loc, type, (short)item.getTypeId(), (short)(item.getAmount() * -1), rawData(item)); + queueBlockBreak(actor, loc, type, data); } /** @@ -170,7 +170,7 @@ public class Consumer extends TimerTask int weapon = 0; if (killer instanceof Player && ((Player)killer).getItemInHand() != null) weapon = ((Player)killer).getItemInHand().getTypeId(); - queueKill(victim.getLocation(), entityName(killer), entityName(victim), weapon); + queueKill(victim.getLocation(), Actor.actorFromEntity(killer), Actor.actorFromEntity(victim), weapon); } /** @@ -180,10 +180,10 @@ public class Consumer extends TimerTask * @param victim * Can't be null */ - public void queueKill(String killer, Entity victim) { + public void queueKill(Actor killer, Entity victim) { if (killer == null || victim == null) return; - queueKill(victim.getLocation(), killer, entityName(victim), 0); + queueKill(victim.getLocation(), killer, Actor.actorFromEntity(victim), 0); } /** @@ -198,24 +198,24 @@ public class Consumer extends TimerTask * @deprecated Use {@link #queueKill(Location,String,String,int)} instead */ @Deprecated - public void queueKill(World world, String killerName, String victimName, int weapon) { - queueKill(new Location(world, 0, 0, 0), killerName, victimName, weapon); + public void queueKill(World world, Actor killer, Actor victim, int weapon) { + queueKill(new Location(world, 0, 0, 0), killer, victim, weapon); } /** * @param location * Location of the victim. - * @param killerName - * Name of the killer. Can be null. - * @param victimName - * Name of the victim. Can't be null. + * @param killer + * Killer Actor. Can be null. + * @param victim + * Victim Actor. Can't be null. * @param weapon * Item id of the weapon. 0 for no weapon. */ - public void queueKill(Location location, String killerName, String victimName, int weapon) { - if (victimName == null || !isLogged(location.getWorld())) + public void queueKill(Location location, Actor killer, Actor victim, int weapon) { + if (victim == null || !isLogged(location.getWorld())) return; - queue.add(new KillRow(location, killerName == null ? null : killerName.replaceAll("[^a-zA-Z0-9_]", ""), victimName.replaceAll("[^a-zA-Z0-9_]", ""), weapon)); + queue.add(new KillRow(location, killer == null ? null : killer, victim, weapon)); } /** @@ -224,14 +224,14 @@ public class Consumer extends TimerTask * @param lines * The four lines on the sign. */ - public void queueSignBreak(String playerName, Location loc, int type, byte data, String[] lines) { + public void queueSignBreak(Actor actor, Location loc, int type, byte data, String[] lines) { if (type != 63 && type != 68 || lines == null || lines.length != 4) return; - queueBlock(playerName, loc, type, 0, data, lines[0] + "\0" + lines[1] + "\0" + lines[2] + "\0" + lines[3], null); + queueBlock(actor, loc, type, 0, data, lines[0] + "\0" + lines[1] + "\0" + lines[2] + "\0" + lines[3], null); } - public void queueSignBreak(String playerName, Sign sign) { - queueSignBreak(playerName, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getTypeId(), sign.getRawData(), sign.getLines()); + public void queueSignBreak(Actor actor, Sign sign) { + queueSignBreak(actor, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getTypeId(), sign.getRawData(), sign.getLines()); } /** @@ -240,17 +240,17 @@ public class Consumer extends TimerTask * @param lines * The four lines on the sign. */ - public void queueSignPlace(String playerName, Location loc, int type, byte data, String[] lines) { + public void queueSignPlace(Actor actor, Location loc, int type, byte data, String[] lines) { if (type != 63 && type != 68 || lines == null || lines.length != 4) return; - queueBlock(playerName, loc, 0, type, data, lines[0] + "\0" + lines[1] + "\0" + lines[2] + "\0" + lines[3], null); + queueBlock(actor, loc, 0, type, data, lines[0] + "\0" + lines[1] + "\0" + lines[2] + "\0" + lines[3], null); } - public void queueSignPlace(String playerName, Sign sign) { - queueSignPlace(playerName, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getTypeId(), sign.getRawData(), sign.getLines()); + public void queueSignPlace(Actor actor, Sign sign) { + queueSignPlace(actor, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getTypeId(), sign.getRawData(), sign.getLines()); } - public void queueChat(String player, String message) { + public void queueChat(Actor player, String message) { for (String ignored : Config.ignoredChat) { if (message.startsWith(ignored)) { return; @@ -289,12 +289,12 @@ public class Consumer extends TimerTask final Row r = queue.poll(); if (r == null) continue; - for (final String player : r.getPlayers()) { - if (!playerIds.containsKey(player)) { - if (!addPlayer(state, player)) { - if (!failedPlayers.contains(player)) { - failedPlayers.add(player); - getLogger().warning("[Consumer] Failed to add player " + player); + for (final Actor actor : r.getActors()) { + if (!playerIds.containsKey(actor)) { + if (!addPlayer(state, actor)) { + if (!failedPlayers.contains(actor)) { + failedPlayers.add(actor); + getLogger().warning("[Consumer] Failed to add player " + actor.getName()); } continue process; } @@ -339,7 +339,7 @@ public class Consumer extends TimerTask public void writeToFile() throws FileNotFoundException { final long time = System.currentTimeMillis(); - final Set insertedPlayers = new HashSet(); + final Set insertedPlayers = new HashSet(); int counter = 0; new File("plugins/LogBlock/import/").mkdirs(); PrintWriter writer = new PrintWriter(new File("plugins/LogBlock/import/queue-" + time + "-0.sql")); @@ -347,11 +347,11 @@ public class Consumer extends TimerTask final Row r = queue.poll(); if (r == null) continue; - for (final String player : r.getPlayers()) - if (!playerIds.containsKey(player) && !insertedPlayers.contains(player)) { + for (final Actor actor : r.getActors()) + if (!playerIds.containsKey(actor) && !insertedPlayers.contains(actor)) { // Odd query contruction is to work around innodb auto increment behaviour - bug #492 - writer.println("INSERT IGNORE INTO `lb-players` (playername) SELECT '" + player + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE playername = '" + player + "') LIMIT 1;"); - insertedPlayers.add(player); + writer.println("INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + actor.getName() + "','" + actor.getUUID() + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + actor.getUUID() + "') LIMIT 1;"); + insertedPlayers.add(actor); } for (final String insert : r.getInserts()) writer.println(insert); @@ -378,26 +378,28 @@ public class Consumer extends TimerTask return true; } - private boolean addPlayer(Statement state, String playerName) throws SQLException { + private boolean addPlayer(Statement state, Actor actor) throws SQLException { // Odd query contruction is to work around innodb auto increment behaviour - bug #492 - state.execute("INSERT IGNORE INTO `lb-players` (playername) SELECT '" + playerName + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE playername = '" + playerName + "') LIMIT 1;"); - final ResultSet rs = state.executeQuery("SELECT playerid FROM `lb-players` WHERE playername = '" + playerName + "'"); + String name = actor.getName(); + String uuid = actor.getUUID(); + state.execute("INSERT IGNORE INTO `lb-players` (playername,UUID) SELECT '" + name + "','" + uuid + "' FROM `lb-players` WHERE NOT EXISTS (SELECT NULL FROM `lb-players` WHERE UUID = '" + uuid + "') LIMIT 1;"); + final ResultSet rs = state.executeQuery("SELECT playerid FROM `lb-players` WHERE UUID = '" + uuid + "'"); if (rs.next()) - playerIds.put(playerName, rs.getInt(1)); + playerIds.put(actor, rs.getInt(1)); rs.close(); - return playerIds.containsKey(playerName); + return playerIds.containsKey(actor); } - private void queueBlock(String playerName, Location loc, int typeBefore, int typeAfter, byte data, String signtext, ChestAccess ca) { + private void queueBlock(Actor actor, Location loc, int typeBefore, int typeAfter, byte data, String signtext, ChestAccess ca) { if (Config.fireCustomEvents) { // Create and call the event - BlockChangePreLogEvent event = new BlockChangePreLogEvent(playerName, loc, typeBefore, typeAfter, data, signtext, ca); + BlockChangePreLogEvent event = new BlockChangePreLogEvent(actor, loc, typeBefore, typeAfter, data, signtext, ca); logblock.getServer().getPluginManager().callEvent(event); if (event.isCancelled()) return; // Update variables - playerName = event.getOwner(); + actor = event.getOwnerActor(); loc = event.getLocation(); typeBefore = event.getTypeBefore(); typeAfter = event.getTypeAfter(); @@ -406,31 +408,37 @@ public class Consumer extends TimerTask ca = event.getChestAccess(); } // Do this last so LogBlock still has final say in what is being added - if (playerName == null || loc == null || typeBefore < 0 || typeAfter < 0 || (Config.safetyIdCheck && (typeBefore > 255 || typeAfter > 255)) || hiddenPlayers.contains(playerName.toLowerCase()) || !isLogged(loc.getWorld()) || typeBefore != typeAfter && hiddenBlocks.contains(typeBefore) && hiddenBlocks.contains(typeAfter)) return; - queue.add(new BlockRow(loc, playerName.replaceAll("[^a-zA-Z0-9_]", ""), typeBefore, typeAfter, data, signtext, ca)); + if (actor == null || loc == null || typeBefore < 0 || typeAfter < 0 || (Config.safetyIdCheck && (typeBefore > 255 || typeAfter > 255)) || hiddenPlayers.contains(actor.getName().toLowerCase()) || !isLogged(loc.getWorld()) || typeBefore != typeAfter && hiddenBlocks.contains(typeBefore) && hiddenBlocks.contains(typeAfter)) return; + queue.add(new BlockRow(loc, actor, typeBefore, typeAfter, data, signtext, ca)); } - private String playerID(String playerName) { - if (playerName == null) + private String playerID(Actor actor) { + if (actor == null) return "NULL"; - final Integer id = playerIds.get(playerName); + final Integer id = playerIds.get(actor); if (id != null) return id.toString(); - return "(SELECT playerid FROM `lb-players` WHERE playername = '" + playerName + "')"; + return "(SELECT playerid FROM `lb-players` WHERE UUID = '" + actor.getUUID() + "')"; } - private Integer playerIDAsInt(String playerName) { - if (playerName == null) { + private Integer playerIDAsInt(Actor actor) { + if (actor == null) { return null; } - return playerIds.get(playerName); + return playerIds.get(actor); } private static interface Row { String[] getInserts(); + /** + * + * @deprecated - Names are not guaranteed to be unique. Use {@link #getActors() } + */ String[] getPlayers(); + + Actor[] getActors(); } private interface PreparedStatementRow extends Row @@ -445,15 +453,15 @@ public class Consumer extends TimerTask { private Connection connection; - public BlockRow(Location loc, String playerName, int replaced, int type, byte data, String signtext, ChestAccess ca) { - super(System.currentTimeMillis() / 1000, loc, playerName, replaced, type, data, signtext, ca); + public BlockRow(Location loc, Actor actor, int replaced, int type, byte data, String signtext, ChestAccess ca) { + super(System.currentTimeMillis() / 1000, loc, actor, replaced, type, data, signtext, ca); } @Override public String[] getInserts() { final String table = getWorldConfig(loc.getWorld()).table; final String[] inserts = new String[ca != null || signtext != null ? 2 : 1]; - inserts[0] = "INSERT INTO `" + table + "` (date, playerid, replaced, type, data, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(playerName) + ", " + replaced + ", " + type + ", " + data + ", '" + loc.getBlockX() + "', " + loc.getBlockY() + ", '" + loc.getBlockZ() + "');"; + inserts[0] = "INSERT INTO `" + table + "` (date, playerid, replaced, type, data, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(actor) + ", " + replaced + ", " + type + ", " + data + ", '" + loc.getBlockX() + "', " + loc.getBlockY() + ", '" + loc.getBlockZ() + "');"; if (signtext != null) { inserts[1] = "INSERT INTO `" + table + "-sign` (id, signtext) values (LAST_INSERT_ID(), '" + signtext.replace("\\", "\\\\").replace("'", "\\'") + "');"; } @@ -464,7 +472,12 @@ public class Consumer extends TimerTask @Override public String[] getPlayers() { - return new String[]{playerName}; + return new String[]{actor.getName()}; + } + + @Override + public Actor[] getActors() { + return new Actor[]{actor}; } @Override @@ -479,7 +492,7 @@ public class Consumer extends TimerTask PreparedStatement ps1 = null; PreparedStatement ps = null; try { - ps1 = connection.prepareStatement("INSERT INTO `" + table + "` (date, playerid, replaced, type, data, x, y, z) VALUES(FROM_UNIXTIME(?), " + playerID(playerName) + ", ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); + ps1 = connection.prepareStatement("INSERT INTO `" + table + "` (date, playerid, replaced, type, data, x, y, z) VALUES(FROM_UNIXTIME(?), " + playerID(actor) + ", ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS); ps1.setLong(1, date ); ps1.setInt(2, replaced); ps1.setInt(3, type); @@ -538,11 +551,11 @@ public class Consumer extends TimerTask private class KillRow implements Row { final long date; - final String killer, victim; + final Actor killer, victim; final int weapon; final Location loc; - KillRow(Location loc, String attacker, String defender, int weapon) { + KillRow(Location loc, Actor attacker, Actor defender, int weapon) { date = System.currentTimeMillis() / 1000; this.loc = loc; killer = attacker; @@ -557,7 +570,12 @@ public class Consumer extends TimerTask @Override public String[] getPlayers() { - return new String[]{killer, victim}; + return new String[]{killer.getName(), victim.getName()}; + } + + @Override + public Actor[] getActors() { + return new Actor[]{killer,victim}; } } @@ -565,18 +583,23 @@ public class Consumer extends TimerTask { private Connection connection; - ChatRow(String player, String message) { + ChatRow(Actor player, String message) { super(player, message); } @Override public String[] getInserts() { - return new String[]{"INSERT INTO `lb-chat` (date, playerid, message) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(playerName) + ", '" + message.replace("\\", "\\\\").replace("'", "\\'") + "');"}; + return new String[]{"INSERT INTO `lb-chat` (date, playerid, message) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(player) + ", '" + message.replace("\\", "\\\\").replace("'", "\\'") + "');"}; } @Override public String[] getPlayers() { - return new String[]{playerName}; + return new String[]{player.getName()}; + } + + @Override + public Actor[] getActors() { + return new Actor[]{player}; } @Override @@ -590,9 +613,9 @@ public class Consumer extends TimerTask Integer id; String sql = "INSERT INTO `lb-chat` (date, playerid, message) VALUES (FROM_UNIXTIME(?), "; - if ((id = playerIDAsInt(playerName)) == null) { + if ((id = playerIDAsInt(player)) == null) { noID = true; - sql += playerID(playerName) + ", "; + sql += playerID(player) + ", "; } else { sql += "?, "; } @@ -627,45 +650,55 @@ public class Consumer extends TimerTask private class PlayerJoinRow implements Row { - private final String playerName; + private final Actor player; private final long lastLogin; private final String ip; PlayerJoinRow(Player player) { - playerName = player.getName(); + this.player = Actor.actorFromEntity(player); lastLogin = System.currentTimeMillis() / 1000; ip = player.getAddress().toString().replace("'", "\\'"); } @Override public String[] getInserts() { - return new String[]{"UPDATE `lb-players` SET lastlogin = FROM_UNIXTIME(" + lastLogin + "), firstlogin = IF(firstlogin = 0, FROM_UNIXTIME(" + lastLogin + "), firstlogin), ip = '" + ip + "' WHERE " + (playerIds.containsKey(playerName) ? "playerid = " + playerIds.get(playerName) : "playerName = '" + playerName + "'") + ";"}; + return new String[]{"UPDATE `lb-players` SET lastlogin = FROM_UNIXTIME(" + lastLogin + "), firstlogin = IF(firstlogin = 0, FROM_UNIXTIME(" + lastLogin + "), firstlogin), ip = '" + ip + "', playername = '" + player.getName() + "' WHERE UUID = '" + player.getUUID() + "';"}; } @Override public String[] getPlayers() { - return new String[]{playerName}; + return new String[]{player.getName()}; + } + + @Override + public Actor[] getActors() { + return new Actor[]{player}; } } private class PlayerLeaveRow implements Row - { - private final String playerName; + {; private final long leaveTime; + private final Actor actor; PlayerLeaveRow(Player player) { - playerName = player.getName(); leaveTime = System.currentTimeMillis() / 1000; + actor = Actor.actorFromEntity(player); } @Override public String[] getInserts() { - return new String[]{"UPDATE `lb-players` SET onlinetime = onlinetime + TIMESTAMPDIFF(SECOND, lastlogin, FROM_UNIXTIME('" + leaveTime + "')) WHERE lastlogin > 0 && " + (playerIds.containsKey(playerName) ? "playerid = " + playerIds.get(playerName) : "playerName = '" + playerName + "'") + ";"}; + return new String[]{"UPDATE `lb-players` SET onlinetime = onlinetime + TIMESTAMPDIFF(SECOND, lastlogin, FROM_UNIXTIME('" + leaveTime + "')), playername = '" + actor.getName() + "' WHERE lastlogin > 0 && UUID = '" + actor.getUUID() + "';"}; } @Override public String[] getPlayers() { - return new String[]{playerName}; + return new String[]{actor.getName()}; + } + + @Override + public Actor[] getActors() { + return new Actor[]{actor}; } } } diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 86df1b0..46b1a3b 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -24,7 +24,7 @@ import de.diddiz.LogBlock.listeners.StructureGrowLogging; import de.diddiz.LogBlock.listeners.ToolListener; import de.diddiz.LogBlock.listeners.WitherLogging; import de.diddiz.util.MySQLConnectionPool; -import de.diddiz.worldedit.LogBlockEditSessionFactory; +//import de.diddiz.worldedit.LogBlockEditSessionFactory; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -109,9 +109,9 @@ public class LogBlock extends JavaPlugin } if (noDb) return; - if (pm.getPlugin("WorldEdit") != null) { - LogBlockEditSessionFactory.initialize(this); - } +// if (pm.getPlugin("WorldEdit") != null) { +// LogBlockEditSessionFactory.initialize(this); +// } commandsHandler = new CommandsHandler(this); getCommand("lb").setExecutor(commandsHandler); if (enableAutoClearLog && autoClearLogDelay > 0) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index 4de1977..cd07aab 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -69,7 +69,7 @@ public final class QueryParams implements Cloneable if (needDate) select += "date, "; if (needPlayer) - select += "playername, "; + select += "playername, UUID,"; if (needMessage) select += "message, "; select = select.substring(0, select.length() - 2); @@ -110,7 +110,7 @@ public final class QueryParams implements Cloneable return select + " " + from + getWhere() + "ORDER BY date " + order + ", id " + order + " " + getLimit(); } else if (sum == SummarizationMode.PLAYERS) - return "SELECT playername, SUM(kills) AS kills, SUM(killed) AS killed FROM ((SELECT killer AS playerid, count(*) AS kills, 0 as killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY killer) UNION (SELECT victim AS playerid, 0 as kills, count(*) AS killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY victim)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(kills) + SUM(killed) " + order + " " + getLimit(); + return "SELECT playername, UUID, SUM(kills) AS kills, SUM(killed) AS killed FROM ((SELECT killer AS playerid, count(*) AS kills, 0 as killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY killer) UNION (SELECT victim AS playerid, 0 as kills, count(*) AS killed FROM `" + getTable() + "-kills` INNER JOIN `lb-players` as killers ON (killer=killers.playerid) INNER JOIN `lb-players` as victims ON (victim=victims.playerid) " + getWhere(BlockChangeType.KILLS) + "GROUP BY victim)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(kills) + SUM(killed) " + order + " " + getLimit(); } if (sum == SummarizationMode.NONE) { String select = "SELECT "; @@ -126,7 +126,7 @@ public final class QueryParams implements Cloneable if (needData) select += "data, "; if (needPlayer) - select += "playername, "; + select += "playername, UUID, "; if (needCoords) select += "x, y, z, "; if (needSignText) diff --git a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java index 089c2db..5e7cd61 100644 --- a/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java +++ b/src/main/java/de/diddiz/LogBlock/SummedBlockChanges.java @@ -12,11 +12,14 @@ public class SummedBlockChanges implements LookupCacheElement private final String group; private final int created, destroyed; private final float spaceFactor; + private final Actor actor; public SummedBlockChanges(ResultSet rs, QueryParams p, float spaceFactor) throws SQLException { - group = p.sum == SummarizationMode.PLAYERS ? rs.getString(1) : materialName(rs.getInt(1)); - created = rs.getInt(2); - destroyed = rs.getInt(3); + // Actor currently useless here as we don't yet output UUID in results anywhere + actor = p.sum == SummarizationMode.PLAYERS ? new Actor(rs) : null; + group = actor == null ? materialName(rs.getInt("type")) : actor.getName(); + created = rs.getInt("created"); + destroyed = rs.getInt("destroyed"); this.spaceFactor = spaceFactor; } diff --git a/src/main/java/de/diddiz/LogBlock/SummedKills.java b/src/main/java/de/diddiz/LogBlock/SummedKills.java old mode 100755 new mode 100644 index 3dba238..5e3d702 --- a/src/main/java/de/diddiz/LogBlock/SummedKills.java +++ b/src/main/java/de/diddiz/LogBlock/SummedKills.java @@ -1,22 +1,20 @@ package de.diddiz.LogBlock; -import static de.diddiz.util.MaterialName.materialName; import static de.diddiz.util.Utils.spaces; import java.sql.ResultSet; import java.sql.SQLException; import org.bukkit.Location; -import de.diddiz.LogBlock.QueryParams.SummarizationMode; public class SummedKills implements LookupCacheElement { - private final String playerName; + private final Actor player; private final int kills, killed; private final float spaceFactor; public SummedKills(ResultSet rs, QueryParams p, float spaceFactor) throws SQLException { - playerName = rs.getString(1); - kills = rs.getInt(2); - killed = rs.getInt(3); + player = new Actor(rs); + kills = rs.getInt("kills"); + killed = rs.getInt("killed"); this.spaceFactor = spaceFactor; } @@ -27,6 +25,6 @@ public class SummedKills implements LookupCacheElement @Override public String getMessage() { - return kills + spaces((int)((6 - String.valueOf(kills).length()) / spaceFactor)) + killed + spaces((int)((7 - String.valueOf(killed).length()) / spaceFactor)) + playerName; + return kills + spaces((int)((6 - String.valueOf(kills).length()) / spaceFactor)) + killed + spaces((int)((7 - String.valueOf(killed).length()) / spaceFactor)) + player.getName(); } } diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 6c334dc..5f85a15 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -13,15 +13,24 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.logging.Level; +import java.util.ArrayList; +import java.util.List; +import java.util.Map.Entry; import static de.diddiz.LogBlock.config.Config.getLoggedWorlds; import static de.diddiz.LogBlock.config.Config.isLogging; import static de.diddiz.util.BukkitUtils.friendlyWorldname; +import de.diddiz.util.UUIDFetcher; +import java.util.HashMap; +import java.util.Map; +import java.util.UUID; +import java.util.logging.Logger; import static org.bukkit.Bukkit.getLogger; class Updater { private final LogBlock logblock; + final int UUID_CONVERT_BATCH_SIZE = 100; Updater(LogBlock logblock) { this.logblock = logblock; @@ -256,6 +265,77 @@ class Updater config.set("version", "1.81"); } + if (config.getString("version").compareTo("1.90") < 0) { + getLogger().info("Updating tables to 1.9 ..."); + getLogger().info("Importing UUIDs for large databases may take some time"); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + st.execute("ALTER TABLE `lb-players` ADD `UUID` VARCHAR(36) NOT NULL"); + } catch (final SQLException ex) { + // Error 1060 is MySQL error "column already exists". We want to continue with import if we get that error + if (ex.getErrorCode() != 1060) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + } + try { + ResultSet rs; + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + // Start by assuming anything with no onlinetime is not a player + st.execute("UPDATE `lb-players` SET UUID = CONCAT ('log_',playername) WHERE onlinetime=0 AND LENGTH(UUID) = 0"); + // Tell people how many are needing converted + rs = st.executeQuery("SELECT COUNT(playername) FROM `lb-players` WHERE LENGTH(UUID)=0"); + rs.next(); + String total = Integer.toString(rs.getInt(1)); + getLogger().info(total + " players to convert"); + int done = 0; + + conn.setAutoCommit(false); + Map players = new HashMap(); + List names = new ArrayList(UUID_CONVERT_BATCH_SIZE); + Map response; + rs = st.executeQuery("SELECT playerid,playername FROM `lb-players` WHERE LENGTH(UUID)=0 LIMIT " + Integer.toString(UUID_CONVERT_BATCH_SIZE)); + while (rs.next()) { + do { + players.put(rs.getString(2),rs.getInt(1)); + names.add(rs.getString(2)); + } while (rs.next()); + if (names.size()>0) { + String theUUID; + response = UUIDFetcher.getUUIDs(names); + for (Map.Entry entry : players.entrySet()) { + if (response.get(entry.getKey()) == null) { + theUUID = "noimport_" + entry.getKey(); + getLogger().warning(entry.getKey() + " not found - giving UUID of " + theUUID); + } else { + theUUID = response.get(entry.getKey()).toString(); + } + String thePID = entry.getValue().toString(); + st.execute("UPDATE `lb-players` SET UUID = '" + theUUID + "' WHERE playerid = " + thePID); + done++; + } + conn.commit(); + players.clear(); + names.clear(); + getLogger().info("Processed " + Integer.toString(done) + " out of " + total); + rs = st.executeQuery("SELECT playerid,playername FROM `lb-players` WHERE LENGTH(UUID)=0 LIMIT " + Integer.toString(UUID_CONVERT_BATCH_SIZE)); + } + } + st.close(); + conn.close(); + + } catch (final SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } catch (Exception ex) { + Bukkit.getLogger().log(Level.SEVERE, "[UUID importer]", ex); + return false; + } + config.set("version", "1.90"); + } logblock.saveConfig(); return true; } @@ -267,11 +347,11 @@ class Updater final Statement state = conn.createStatement(); final DatabaseMetaData dbm = conn.getMetaData(); conn.setAutoCommit(true); - createTable(dbm, state, "lb-players", "(playerid INT UNSIGNED NOT NULL AUTO_INCREMENT, playername varchar(32) NOT NULL, firstlogin DATETIME NOT NULL, lastlogin DATETIME NOT NULL, onlinetime INT UNSIGNED NOT NULL, ip varchar(255) NOT NULL, PRIMARY KEY (playerid), UNIQUE (playername))"); + createTable(dbm, state, "lb-players", "(playerid INT UNSIGNED NOT NULL AUTO_INCREMENT, UUID varchar(36) NOT NULL, playername varchar(32) NOT NULL, firstlogin DATETIME NOT NULL, lastlogin DATETIME NOT NULL, onlinetime INT UNSIGNED NOT NULL, ip varchar(255) NOT NULL, PRIMARY KEY (playerid), UNIQUE (UUID))"); // Players table must not be empty or inserts won't work - bug #492 final ResultSet rs = state.executeQuery("SELECT NULL FROM `lb-players` LIMIT 1;"); if (!rs.next()) - state.execute("INSERT IGNORE INTO `lb-players` (playername) VALUES ('dummy_record')"); + state.execute("INSERT IGNORE INTO `lb-players` (UUID,playername) VALUES ('log_dummy_record','dummy_record')"); if (isLogging(Logging.CHAT)) createTable(dbm, state, "lb-chat", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, message VARCHAR(255) NOT NULL, PRIMARY KEY (id), KEY playerid (playerid), FULLTEXT message (message)) ENGINE=MyISAM DEFAULT CHARSET utf8"); for (final WorldConfig wcfg : getLoggedWorlds()) { diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 4c52f1c..fb5553f 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -147,8 +147,8 @@ public class WorldEditor implements Runnable private class Edit extends BlockChange { - public Edit(long time, Location loc, String playerName, int replaced, int type, byte data, String signtext, ChestAccess ca) { - super(time, loc, playerName, replaced, type, data, signtext, ca); + public Edit(long time, Location loc, Actor actor, int replaced, int type, byte data, String signtext, ChestAccess ca) { + super(time, loc, actor, replaced, type, data, signtext, ca); } PerformResult perform() throws WorldEditorException { diff --git a/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java b/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java index fa7c668..e2b8f6c 100644 --- a/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java +++ b/src/main/java/de/diddiz/LogBlock/events/BlockChangePreLogEvent.java @@ -1,4 +1,5 @@ package de.diddiz.LogBlock.events; +import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.ChestAccess; import org.apache.commons.lang.Validate; import org.bukkit.Location; @@ -13,7 +14,7 @@ public class BlockChangePreLogEvent extends PreLogEvent { private String signText; private ChestAccess chestAccess; - public BlockChangePreLogEvent(String owner, Location location, int typeBefore, int typeAfter, byte data, + public BlockChangePreLogEvent(Actor owner, Location location, int typeBefore, int typeAfter, byte data, String signText, ChestAccess chestAccess) { super(owner); diff --git a/src/main/java/de/diddiz/LogBlock/events/PreLogEvent.java b/src/main/java/de/diddiz/LogBlock/events/PreLogEvent.java index 3c12e6b..49c8598 100644 --- a/src/main/java/de/diddiz/LogBlock/events/PreLogEvent.java +++ b/src/main/java/de/diddiz/LogBlock/events/PreLogEvent.java @@ -1,24 +1,36 @@ package de.diddiz.LogBlock.events; +import de.diddiz.LogBlock.Actor; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; public abstract class PreLogEvent extends Event implements Cancellable { protected boolean cancelled = false; - protected String owner; + protected Actor owner; - public PreLogEvent(String owner) { + public PreLogEvent(Actor owner) { - this.owner = owner.replaceAll("[^a-zA-Z0-9_]", ""); + this.owner = owner; } /** * Returns the player/monster/cause involved in this event * * @return Player/monster/cause who is involved in this event + * @deprecated {@link #getOwnerActor() } returns an object encapsulating + * name and uuid. Names are not guaranteed to be unique. */ public String getOwner() { + return owner.getName(); + } + + /** + * Returns the player/monster/cause involved in this event + * + * @return Player/monster/cause who is involved in this event + */ + public Actor getOwnerActor() { return owner; } @@ -27,9 +39,9 @@ public abstract class PreLogEvent extends Event implements Cancellable { * * @param owner The player/monster/cause who is involved in this event */ - public void setOwner(String owner) { + public void setOwner(Actor owner) { - this.owner = owner.replaceAll("[^a-zA-Z0-9_]", ""); + this.owner = owner; } public boolean isCancelled() { diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java index d9dc725..22dad56 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBreakLogging.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; import static de.diddiz.LogBlock.config.Config.getWorldConfig; import static de.diddiz.LogBlock.config.Config.isLogging; import static de.diddiz.util.LoggingUtil.smartLogBlockBreak; @@ -29,33 +30,33 @@ public class BlockBreakLogging extends LoggingListener WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld()); if (wcfg == null) return; - final String playerName = event.getPlayer().getName(); + final Actor actor = Actor.actorFromEntity(event.getPlayer()); final Block origin = event.getBlock(); final int typeId = origin.getTypeId(); final Material type = origin.getType(); if (wcfg.isLogging(Logging.SIGNTEXT) && (typeId == 63 || typeId == 68)) { - consumer.queueSignBreak(playerName, (Sign) origin.getState()); + consumer.queueSignBreak(actor, (Sign) origin.getState()); } else if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.getContainerBlocks().contains(type)) { - consumer.queueContainerBreak(playerName, origin.getState()); + consumer.queueContainerBreak(actor, origin.getState()); } else if (type == Material.ICE) { // When in creative mode ice doesn't form water if (event.getPlayer().getGameMode().equals(GameMode.CREATIVE)) { - consumer.queueBlockBreak(playerName, origin.getState()); + consumer.queueBlockBreak(actor, origin.getState()); } else { - consumer.queueBlockReplace(playerName, origin.getState(), 9, (byte) 0); + consumer.queueBlockReplace(actor, origin.getState(), 9, (byte) 0); } } else { - smartLogBlockBreak(consumer, playerName, origin); + smartLogBlockBreak(consumer, actor, origin); } - smartLogFallables(consumer, playerName, origin); + smartLogFallables(consumer, actor, origin); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerBucketFill(PlayerBucketFillEvent event) { if (isLogging(event.getBlockClicked().getWorld(), Logging.BLOCKBREAK)) { - consumer.queueBlockBreak(event.getPlayer().getName(), event.getBlockClicked().getState()); + consumer.queueBlockBreak(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getState()); } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java index 7119ab4..471eac4 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java @@ -1,13 +1,14 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; import static de.diddiz.LogBlock.config.Config.isLogging; import static de.diddiz.util.LoggingUtil.smartLogBlockBreak; import static de.diddiz.util.LoggingUtil.smartLogFallables; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockBurnEvent; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; public class BlockBurnLogging extends LoggingListener { @@ -18,8 +19,8 @@ public class BlockBurnLogging extends LoggingListener @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockBurn(BlockBurnEvent event) { if (isLogging(event.getBlock().getWorld(), Logging.FIRE)) { - smartLogBlockBreak(consumer, "Fire", event.getBlock()); - smartLogFallables(consumer, "Fire", event.getBlock()); + smartLogBlockBreak(consumer, new Actor("Fire"), event.getBlock()); + smartLogFallables(consumer, new Actor("Fire"), event.getBlock()); } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java index cc65377..58ae7fb 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockPlaceLogging.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; import static de.diddiz.LogBlock.config.Config.getWorldConfig; import static de.diddiz.LogBlock.config.Config.isLogging; @@ -29,14 +30,14 @@ public class BlockPlaceLogging extends LoggingListener final Material type = event.getBlock().getType(); final BlockState before = event.getBlockReplacedState(); final BlockState after = event.getBlockPlaced().getState(); - final String playerName = event.getPlayer().getName(); + final Actor actor = Actor.actorFromEntity(event.getPlayer()); //Handle falling blocks if (BukkitUtils.getRelativeTopFallables().contains(type)) { // Catch placed blocks overwriting something if (before.getType() != Material.AIR) { - consumer.queueBlockBreak(playerName, before); + consumer.queueBlockBreak(actor, before); } Location loc = event.getBlock().getLocation(); @@ -55,9 +56,9 @@ public class BlockPlaceLogging extends LoggingListener // Run this check to avoid false positives if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) { if (finalLoc.getBlock().getType() == Material.AIR || finalLoc.equals(event.getBlock().getLocation())) { - consumer.queueBlockPlace(playerName, finalLoc, type.getId(), event.getBlock().getData()); + consumer.queueBlockPlace(actor, finalLoc, type.getId(), event.getBlock().getData()); } else { - consumer.queueBlockReplace(playerName, finalLoc, finalLoc.getBlock().getTypeId(), finalLoc.getBlock().getData(), type.getId(), event.getBlock().getData()); + consumer.queueBlockReplace(actor, finalLoc, finalLoc.getBlock().getTypeId(), finalLoc.getBlock().getData(), type.getId(), event.getBlock().getData()); } } } @@ -73,9 +74,9 @@ public class BlockPlaceLogging extends LoggingListener @Override public void run() { if (before.getTypeId() == 0) - consumer.queueBlockPlace(playerName, after); + consumer.queueBlockPlace(actor, after); else - consumer.queueBlockReplace(playerName, before, after); + consumer.queueBlockReplace(actor, before, after); } }, 1L); } @@ -84,6 +85,6 @@ public class BlockPlaceLogging extends LoggingListener @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onPlayerBucketEmpty(PlayerBucketEmptyEvent event) { if (isLogging(event.getPlayer().getWorld(), Logging.BLOCKPLACE)) - consumer.queueBlockPlace(event.getPlayer().getName(), event.getBlockClicked().getRelative(event.getBlockFace()).getLocation(), event.getBucket() == Material.WATER_BUCKET ? 9 : 11, (byte)0); + consumer.queueBlockPlace(Actor.actorFromEntity(event.getPlayer()), event.getBlockClicked().getRelative(event.getBlockFace()).getLocation(), event.getBucket() == Material.WATER_BUCKET ? 9 : 11, (byte)0); } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java index b1d0f38..1cac2d0 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockSpreadLogging.java @@ -1,15 +1,15 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; +import static de.diddiz.LogBlock.config.Config.isLogging; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockSpreadEvent; -import static de.diddiz.LogBlock.config.Config.isLogging; - public class BlockSpreadLogging extends LoggingListener { @@ -47,6 +47,6 @@ public class BlockSpreadLogging extends LoggingListener return; } - consumer.queueBlockReplace(name, event.getBlock().getState(), event.getNewState()); + consumer.queueBlockReplace(new Actor(name), event.getBlock().getState(), event.getNewState()); } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChatLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChatLogging.java index 9f24db3..80078c5 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChatLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChatLogging.java @@ -1,13 +1,14 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; import static de.diddiz.LogBlock.config.Config.isLogging; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.player.AsyncPlayerChatEvent; import org.bukkit.event.player.PlayerCommandPreprocessEvent; import org.bukkit.event.server.ServerCommandEvent; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; public class ChatLogging extends LoggingListener { @@ -18,17 +19,17 @@ public class ChatLogging extends LoggingListener @EventHandler(priority = EventPriority.MONITOR) public void onPlayerCommandPreprocess(PlayerCommandPreprocessEvent event) { if (isLogging(event.getPlayer().getWorld(), Logging.CHAT)) - consumer.queueChat(event.getPlayer().getName(), event.getMessage()); + consumer.queueChat(Actor.actorFromEntity(event.getPlayer()), event.getMessage()); } @EventHandler(priority = EventPriority.MONITOR) public void onPlayerChat(AsyncPlayerChatEvent event) { if (isLogging(event.getPlayer().getWorld(), Logging.CHAT)) - consumer.queueChat(event.getPlayer().getName(), event.getMessage()); + consumer.queueChat(Actor.actorFromEntity(event.getPlayer()), event.getMessage()); } @EventHandler(priority = EventPriority.MONITOR) public void onServerCommand(ServerCommandEvent event) { - consumer.queueChat("Console", "/" + event.getCommand()); + consumer.queueChat(new Actor("Console"), "/" + event.getCommand()); } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java index 2be244f..9354556 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ChestAccessLogging.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; import static de.diddiz.LogBlock.config.Config.isLogging; import static de.diddiz.util.BukkitUtils.compareInventories; import static de.diddiz.util.BukkitUtils.compressInventory; @@ -43,7 +44,7 @@ public class ChestAccessLogging extends LoggingListener final ItemStack[] diff = compareInventories(before, after); final Location loc = getInventoryHolderLocation(holder); for (final ItemStack item : diff) { - consumer.queueChestAccess(player.getName(), loc, loc.getWorld().getBlockTypeIdAt(loc), (short)item.getTypeId(), (short)item.getAmount(), rawData(item)); + consumer.queueChestAccess(Actor.actorFromEntity(player), loc, loc.getWorld().getBlockTypeIdAt(loc), (short)item.getTypeId(), (short)item.getAmount(), rawData(item)); } containers.remove(player); } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java index c7a5f03..940359e 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/CreatureInteractLogging.java @@ -1,7 +1,9 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; +import static de.diddiz.LogBlock.config.Config.getWorldConfig; import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.util.BukkitUtils; import org.bukkit.Location; @@ -14,8 +16,6 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityInteractEvent; -import static de.diddiz.LogBlock.config.Config.getWorldConfig; - public class CreatureInteractLogging extends LoggingListener { public CreatureInteractLogging(LogBlock lb) { @@ -42,11 +42,11 @@ public class CreatureInteractLogging extends LoggingListener case SOIL: if (wcfg.isLogging(Logging.CREATURECROPTRAMPLE)) { // 3 = Dirt ID - consumer.queueBlock(entityType.getName(), loc, typeId, 3, blockData); + consumer.queueBlock(Actor.actorFromEntity(entityType), loc, typeId, 3, blockData); // Log the crop on top as being broken Block trampledCrop = clicked.getRelative(BlockFace.UP); if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) { - consumer.queueBlockBreak("CreatureTrample", trampledCrop.getState()); + consumer.queueBlockBreak(new Actor("CreatureTrample"), trampledCrop.getState()); } } break; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java index 4adcd10..1f4bc21 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/EndermenLogging.java @@ -1,12 +1,13 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; import static de.diddiz.LogBlock.config.Config.isLogging; import org.bukkit.entity.Enderman; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityChangeBlockEvent; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; public class EndermenLogging extends LoggingListener { @@ -17,6 +18,6 @@ public class EndermenLogging extends LoggingListener @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityChangeBlock(EntityChangeBlockEvent event) { if (event.getEntity() instanceof Enderman && isLogging(event.getBlock().getWorld(), Logging.ENDERMEN)) - consumer.queueBlockReplace("Enderman", event.getBlock().getState(), event.getTo().getId(), (byte)0); // Figure out how to get the data of the placed block; + consumer.queueBlockReplace(new Actor("Enderman"), event.getBlock().getState(), event.getTo().getId(), (byte)0); // Figure out how to get the data of the placed block; } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index f663b32..c2d6bac 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -1,8 +1,13 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; +import static de.diddiz.LogBlock.config.Config.getWorldConfig; +import static de.diddiz.LogBlock.config.Config.logCreeperExplosionsAsPlayerWhoTriggeredThese; import de.diddiz.LogBlock.config.WorldConfig; +import static de.diddiz.util.BukkitUtils.getContainerBlocks; +import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.entity.Creeper; @@ -10,19 +15,14 @@ import org.bukkit.entity.EnderDragon; import org.bukkit.entity.Entity; import org.bukkit.entity.Fireball; import org.bukkit.entity.Ghast; -import org.bukkit.entity.minecart.ExplosiveMinecart; import org.bukkit.entity.Player; import org.bukkit.entity.TNTPrimed; import org.bukkit.entity.Wither; import org.bukkit.entity.WitherSkull; +import org.bukkit.entity.minecart.ExplosiveMinecart; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityExplodeEvent; -import org.bukkit.Material; - -import static de.diddiz.LogBlock.config.Config.getWorldConfig; -import static de.diddiz.LogBlock.config.Config.logCreeperExplosionsAsPlayerWhoTriggeredThese; -import static de.diddiz.util.BukkitUtils.getContainerBlocks; public class ExplosionLogging extends LoggingListener { @@ -34,7 +34,7 @@ public class ExplosionLogging extends LoggingListener public void onEntityExplode(EntityExplodeEvent event) { final WorldConfig wcfg = getWorldConfig(event.getLocation().getWorld()); if (wcfg != null) { - String name = "Explosion"; + Actor actor = new Actor("Explosion"); Entity source = event.getEntity(); if (source == null) { if (!wcfg.isLogging(Logging.MISCEXPLOSION)) @@ -42,19 +42,19 @@ public class ExplosionLogging extends LoggingListener } else if (source instanceof TNTPrimed) { if (!wcfg.isLogging(Logging.TNTEXPLOSION)) return; - name = "TNT"; + actor = new Actor("TNT"); } else if (source instanceof ExplosiveMinecart) { if (!wcfg.isLogging(Logging.TNTMINECARTEXPLOSION)) return; - name = "TNTMinecart"; + actor = new Actor("TNTMinecart"); } else if (source instanceof Creeper) { if (!wcfg.isLogging(Logging.CREEPEREXPLOSION)) return; if (logCreeperExplosionsAsPlayerWhoTriggeredThese) { final Entity target = ((Creeper) source).getTarget(); - name = target instanceof Player ? ((Player)target).getName() : "Creeper"; + actor = target instanceof Player ? Actor.actorFromEntity(target) : new Actor("Creeper"); } else - name = "Creeper"; + new Actor("Creeper"); } else if (source instanceof Fireball) { Fireball fireball = (Fireball) source; Entity shooter = fireball.getShooter(); @@ -65,25 +65,25 @@ public class ExplosionLogging extends LoggingListener if (!wcfg.isLogging(Logging.GHASTFIREBALLEXPLOSION)) { return; } - name = "Ghast"; + actor = Actor.actorFromEntity(shooter); } else if (shooter instanceof Wither) { if (!wcfg.isLogging(Logging.WITHER)) { return; } - name = "Wither"; + actor = Actor.actorFromEntity(shooter); } } else if (source instanceof EnderDragon) { if (!wcfg.isLogging(Logging.ENDERDRAGON)) return; - name = "EnderDragon"; + actor = Actor.actorFromEntity(source); } else if (source instanceof Wither) { if(!wcfg.isLogging(Logging.WITHER)) return; - name = "Wither"; + actor = Actor.actorFromEntity(source); } else if (source instanceof WitherSkull) { if(!wcfg.isLogging(Logging.WITHER_SKULL)) return; - name = "WitherSkull"; + actor = Actor.actorFromEntity(source); } else { if (!wcfg.isLogging(Logging.MISCEXPLOSION)) return; @@ -91,11 +91,11 @@ public class ExplosionLogging extends LoggingListener for (final Block block : event.blockList()) { final int type = block.getTypeId(); if (wcfg.isLogging(Logging.SIGNTEXT) & (type == 63 || type == 68)) - consumer.queueSignBreak(name, (Sign)block.getState()); + consumer.queueSignBreak(actor, (Sign)block.getState()); else if (wcfg.isLogging(Logging.CHESTACCESS) && (getContainerBlocks().contains(Material.getMaterial(type)))) - consumer.queueContainerBreak(name, block.getState()); + consumer.queueContainerBreak(actor, block.getState()); else - consumer.queueBlockBreak(name, block.getState()); + consumer.queueBlockBreak(actor, block.getState()); } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java index 5df6411..d64bfb6 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/FluidFlowLogging.java @@ -1,6 +1,10 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; import static de.diddiz.LogBlock.config.Config.getWorldConfig; +import de.diddiz.LogBlock.config.WorldConfig; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -9,9 +13,6 @@ import org.bukkit.block.BlockFace; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockFromToEvent; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import de.diddiz.LogBlock.config.WorldConfig; public class FluidFlowLogging extends LoggingListener { @@ -32,37 +33,37 @@ public class FluidFlowLogging extends LoggingListener if (typeFrom == 10 || typeFrom == 11) { if (canFlow && wcfg.isLogging(Logging.LAVAFLOW)) { if (isSurroundedByWater(to) && event.getBlock().getData() <= 2) - consumer.queueBlockReplace("LavaFlow", to.getState(), 4, (byte)0); + consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), 4, (byte)0); else if (typeTo == 0) { - consumer.queueBlockPlace("LavaFlow", to.getLocation(), 10, (byte)(event.getBlock().getData() + 1)); + consumer.queueBlockPlace(new Actor("LavaFlow"), to.getLocation(), 10, (byte)(event.getBlock().getData() + 1)); } else { - consumer.queueBlockReplace("LavaFlow", to.getState(), 10, (byte)(event.getBlock().getData() + 1)); + consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), 10, (byte)(event.getBlock().getData() + 1)); } } else if (typeTo == 8 || typeTo == 9) { if (event.getFace() == BlockFace.DOWN) { - consumer.queueBlockReplace("LavaFlow", to.getState(), 1, (byte)0); + consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), 1, (byte)0); } else { - consumer.queueBlockReplace("LavaFlow", to.getState(), 4, (byte)0); + consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), 4, (byte)0); } } } else if ((typeFrom == 8 || typeFrom == 9) && wcfg.isLogging(Logging.WATERFLOW)) { if (typeTo == 0) { - consumer.queueBlockPlace("WaterFlow", to.getLocation(), 8, (byte)(event.getBlock().getData() + 1)); + consumer.queueBlockPlace(new Actor("WaterFlow"), to.getLocation(), 8, (byte)(event.getBlock().getData() + 1)); } else if (nonFluidProofBlocks.contains(typeTo)) { - consumer.queueBlockReplace("WaterFlow", to.getState(), 8, (byte)(event.getBlock().getData() + 1)); + consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), 8, (byte)(event.getBlock().getData() + 1)); } else if (typeTo == 10 || typeTo == 11) { if (to.getData() == 0) { - consumer.queueBlockReplace("WaterFlow", to.getState(), 49, (byte)0); + consumer.queueBlockReplace(new Actor("WaterFlow"), to.getState(), 49, (byte)0); } else if (event.getFace() == BlockFace.DOWN) { - consumer.queueBlockReplace("LavaFlow", to.getState(), 1, (byte)0); + consumer.queueBlockReplace(new Actor("LavaFlow"), to.getState(), 1, (byte)0); } } if (typeTo == 0 || nonFluidProofBlocks.contains(typeTo)) { for (final BlockFace face : new BlockFace[]{BlockFace.DOWN, BlockFace.NORTH, BlockFace.WEST, BlockFace.EAST, BlockFace.SOUTH}) { final Block lower = to.getRelative(face); if (lower.getTypeId() == 10 || lower.getTypeId() == 11) { - consumer.queueBlockReplace("WaterFlow", lower.getState(), lower.getData() == 0 ? 49 : 4, (byte)0); + consumer.queueBlockReplace(new Actor("WaterFlow"), lower.getState(), lower.getData() == 0 ? 49 : 4, (byte)0); } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java index 4c96dc2..086cb33 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/InteractLogging.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; import static de.diddiz.LogBlock.config.Config.getWorldConfig; import de.diddiz.util.BukkitUtils; @@ -15,6 +16,7 @@ import org.bukkit.event.player.PlayerInteractEvent; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.WorldConfig; +import org.bukkit.entity.EntityType; public class InteractLogging extends LoggingListener { @@ -39,31 +41,31 @@ public class InteractLogging extends LoggingListener case WOOD_BUTTON: case STONE_BUTTON: if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) - consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); break; case FENCE_GATE: case WOODEN_DOOR: case TRAP_DOOR: if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) - consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); break; case CAKE_BLOCK: if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20) - consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); break; case NOTE_BLOCK: if (wcfg.isLogging(Logging.NOTEBLOCKINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) - consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); break; case DIODE_BLOCK_OFF: case DIODE_BLOCK_ON: if (wcfg.isLogging(Logging.DIODEINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) - consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); break; case REDSTONE_COMPARATOR_OFF: case REDSTONE_COMPARATOR_ON: if (wcfg.isLogging(Logging.COMPARATORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) { - consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); } break; case WOOD_PLATE: @@ -71,22 +73,22 @@ public class InteractLogging extends LoggingListener case IRON_PLATE: case GOLD_PLATE: if (wcfg.isLogging(Logging.PRESUREPLATEINTERACT) && event.getAction() == Action.PHYSICAL) { - consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); } break; case TRIPWIRE: if (wcfg.isLogging(Logging.TRIPWIREINTERACT) && event.getAction() == Action.PHYSICAL) { - consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, typeId, blockData); } break; case SOIL: if (wcfg.isLogging(Logging.CROPTRAMPLE) && event.getAction() == Action.PHYSICAL) { // 3 = Dirt ID - consumer.queueBlock(player.getName(), loc, typeId, 3, blockData); + consumer.queueBlock(Actor.actorFromEntity(player), loc, typeId, 3, blockData); // Log the crop on top as being broken Block trampledCrop = clicked.getRelative(BlockFace.UP); if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) { - consumer.queueBlockBreak(player.getName(), trampledCrop.getState()); + consumer.queueBlockBreak(Actor.actorFromEntity(player), trampledCrop.getState()); } } break; diff --git a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java index 491ba34..0a8a7b7 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/KillLogging.java @@ -1,8 +1,12 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.Config.LogKillsLevel; import static de.diddiz.LogBlock.config.Config.isLogging; -import static de.diddiz.LogBlock.config.Config.logKillsLevel; import static de.diddiz.LogBlock.config.Config.logEnvironmentalKills; +import static de.diddiz.LogBlock.config.Config.logKillsLevel; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Monster; @@ -12,9 +16,6 @@ import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityDeathEvent; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import de.diddiz.LogBlock.config.Config.LogKillsLevel; public class KillLogging extends LoggingListener @@ -42,7 +43,7 @@ public class KillLogging extends LoggingListener return; else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster))) return; - consumer.queueKill(event.getCause().toString(),victim); + consumer.queueKill(new Actor(event.getCause().toString()),victim); } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/LeavesDecayLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/LeavesDecayLogging.java index 204749d..253eaa5 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/LeavesDecayLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/LeavesDecayLogging.java @@ -1,13 +1,14 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; import static de.diddiz.LogBlock.config.Config.isLogging; import static de.diddiz.util.LoggingUtil.smartLogBlockBreak; import static de.diddiz.util.LoggingUtil.smartLogFallables; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.LeavesDecayEvent; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; public class LeavesDecayLogging extends LoggingListener { @@ -18,8 +19,8 @@ public class LeavesDecayLogging extends LoggingListener @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onLeavesDecay(LeavesDecayEvent event) { if (isLogging(event.getBlock().getWorld(), Logging.LEAVESDECAY)) { - smartLogBlockBreak(consumer, "LeavesDecay", event.getBlock()); - smartLogFallables(consumer, "LeavesDecay", event.getBlock()); + smartLogBlockBreak(consumer, new Actor("LeavesDecay"), event.getBlock()); + smartLogFallables(consumer, new Actor("LeavesDecay"), event.getBlock()); } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/LockedChestDecayLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/LockedChestDecayLogging.java index 5d3b113..5f1c766 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/LockedChestDecayLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/LockedChestDecayLogging.java @@ -1,11 +1,12 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; import static de.diddiz.LogBlock.config.Config.isLogging; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockFadeEvent; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; public class LockedChestDecayLogging extends LoggingListener { @@ -18,7 +19,7 @@ public class LockedChestDecayLogging extends LoggingListener if (isLogging(event.getBlock().getWorld(), Logging.LOCKEDCHESTDECAY)) { final int type = event.getBlock().getTypeId(); if (type == 95) - consumer.queueBlockReplace("LockedChestDecay", event.getBlock().getState(), event.getNewState()); + consumer.queueBlockReplace(new Actor("LockedChestDecay"), event.getBlock().getState(), event.getNewState()); } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java index 8d4389d..0b2e823 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/SignChangeLogging.java @@ -1,11 +1,13 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; import static de.diddiz.LogBlock.config.Config.isLogging; +import org.bukkit.entity.Entity; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.SignChangeEvent; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; public class SignChangeLogging extends LoggingListener { @@ -16,6 +18,6 @@ public class SignChangeLogging extends LoggingListener @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onSignChange(SignChangeEvent event) { if (isLogging(event.getBlock().getWorld(), Logging.SIGNTEXT)) - consumer.queueSignPlace(event.getPlayer().getName(), event.getBlock().getLocation(), event.getBlock().getTypeId(), event.getBlock().getData(), event.getLines()); + consumer.queueSignPlace(Actor.actorFromEntity(event.getPlayer()), event.getBlock().getLocation(), event.getBlock().getTypeId(), event.getBlock().getData(), event.getLines()); } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/SnowFadeLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/SnowFadeLogging.java index 042d992..e15c638 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/SnowFadeLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/SnowFadeLogging.java @@ -1,11 +1,12 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; import static de.diddiz.LogBlock.config.Config.isLogging; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockFadeEvent; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; public class SnowFadeLogging extends LoggingListener { @@ -18,7 +19,7 @@ public class SnowFadeLogging extends LoggingListener if (isLogging(event.getBlock().getWorld(), Logging.SNOWFADE)) { final int type = event.getBlock().getTypeId(); if (type == 78 || type == 79) - consumer.queueBlockReplace("SnowFade", event.getBlock().getState(), event.getNewState()); + consumer.queueBlockReplace(new Actor("SnowFade"), event.getBlock().getState(), event.getNewState()); } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java index 51bd2f1..f911a56 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/SnowFormLogging.java @@ -1,12 +1,13 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; import static de.diddiz.LogBlock.config.Config.isLogging; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.BlockFormEvent; import org.bukkit.event.block.LeavesDecayEvent; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; public class SnowFormLogging extends LoggingListener { @@ -14,18 +15,18 @@ public class SnowFormLogging extends LoggingListener super(lb); } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onLeavesDecay(LeavesDecayEvent event) { - if (isLogging(event.getBlock().getWorld(), Logging.SNOWFORM)) - consumer.queueBlockBreak("LeavesDecay", event.getBlock().getState()); - } +// @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) +// public void onLeavesDecay(LeavesDecayEvent event) { +// if (isLogging(event.getBlock().getWorld(), Logging.SNOWFORM)) +// consumer.queueBlockBreak("LeavesDecay", event.getBlock().getState()); +// } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockForm(BlockFormEvent event) { if (isLogging(event.getBlock().getWorld(), Logging.SNOWFORM)) { final int type = event.getNewState().getTypeId(); if (type == 78 || type == 79) - consumer.queueBlockReplace("SnowForm", event.getBlock().getState(), event.getNewState()); + consumer.queueBlockReplace(new Actor("SnowForm"), event.getBlock().getState(), event.getNewState()); } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/StructureGrowLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/StructureGrowLogging.java index fc57cde..786acfe 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/StructureGrowLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/StructureGrowLogging.java @@ -1,13 +1,14 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; import static de.diddiz.LogBlock.config.Config.getWorldConfig; +import de.diddiz.LogBlock.config.WorldConfig; import org.bukkit.block.BlockState; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.world.StructureGrowEvent; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; -import de.diddiz.LogBlock.config.WorldConfig; public class StructureGrowLogging extends LoggingListener { @@ -19,18 +20,18 @@ public class StructureGrowLogging extends LoggingListener public void onStructureGrow(StructureGrowEvent event) { final WorldConfig wcfg = getWorldConfig(event.getWorld()); if (wcfg != null) { - final String playerName; + final Actor actor; if (event.getPlayer() != null) { if (!wcfg.isLogging(Logging.BONEMEALSTRUCTUREGROW)) return; - playerName = event.getPlayer().getName(); + actor = Actor.actorFromEntity(event.getPlayer()); } else { if (!wcfg.isLogging(Logging.NATURALSTRUCTUREGROW)) return; - playerName = "NaturalGrow"; + actor = new Actor("NaturalGrow"); } for (final BlockState state : event.getBlocks()) - consumer.queueBlockReplace(playerName, state.getBlock().getState(), state); + consumer.queueBlockReplace(actor, state.getBlock().getState(), state); } } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java index 260ff09..ec5dad2 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/WitherLogging.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock.listeners; +import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import org.bukkit.entity.Wither; @@ -18,6 +19,6 @@ public class WitherLogging extends LoggingListener @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onEntityChangeBlock(EntityChangeBlockEvent event) { if (event.getEntity() instanceof Wither && isLogging(event.getBlock().getWorld(), Logging.WITHER)) - consumer.queueBlockReplace("Wither", event.getBlock().getState(), event.getTo().getId(), event.getData()); // Wither walked through a block. + consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), event.getBlock().getState(), event.getTo().getId(), event.getData()); // Wither walked through a block. } } diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index be6c0c3..8dca8be 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -1,6 +1,10 @@ package de.diddiz.util; +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.Consumer; +import de.diddiz.LogBlock.Logging; import static de.diddiz.LogBlock.config.Config.getWorldConfig; +import de.diddiz.LogBlock.config.WorldConfig; import java.util.List; import org.bukkit.Location; import org.bukkit.Material; @@ -17,13 +21,10 @@ import org.bukkit.material.RedstoneTorch; import org.bukkit.material.Torch; import org.bukkit.material.TrapDoor; import org.bukkit.material.TripwireHook; -import de.diddiz.LogBlock.Consumer; -import de.diddiz.LogBlock.Logging; -import de.diddiz.LogBlock.config.WorldConfig; public class LoggingUtil { - public static void smartLogFallables(Consumer consumer, String playerName, Block origin) { + public static void smartLogFallables(Consumer consumer, Actor actor, Block origin) { WorldConfig wcfg = getWorldConfig(origin.getWorld()); if (wcfg == null) return; @@ -35,7 +36,7 @@ public class LoggingUtil { while (BukkitUtils.getRelativeTopFallables().contains(checkBlock.getType())) { // Record this block as falling - consumer.queueBlockBreak(playerName, checkBlock.getState()); + consumer.queueBlockBreak(actor, checkBlock.getState()); // Guess where the block is going (This could be thrown of by explosions, but it is better than nothing) Location loc = origin.getLocation(); @@ -52,9 +53,9 @@ public class LoggingUtil { if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) { finalLoc.add(0, up, 0); // Add this here after checking for block breakers if (finalLoc.getBlock().getType() == Material.AIR || BukkitUtils.getRelativeTopFallables().contains(finalLoc.getBlock().getType())) { - consumer.queueBlockPlace(playerName, finalLoc, checkBlock.getTypeId(), checkBlock.getData()); + consumer.queueBlockPlace(actor, finalLoc, checkBlock.getTypeId(), checkBlock.getData()); } else { - consumer.queueBlockReplace(playerName, finalLoc, finalLoc.getBlock().getTypeId(), finalLoc.getBlock().getData(), checkBlock.getTypeId(), checkBlock.getData()); + consumer.queueBlockReplace(actor, finalLoc, finalLoc.getBlock().getTypeId(), finalLoc.getBlock().getData(), checkBlock.getTypeId(), checkBlock.getData()); } up++; } @@ -64,7 +65,7 @@ public class LoggingUtil { } } - public static void smartLogBlockBreak(Consumer consumer, String playerName, Block origin) { + public static void smartLogBlockBreak(Consumer consumer, Actor actor, Block origin) { WorldConfig wcfg = getWorldConfig(origin.getWorld()); if (wcfg == null) return; @@ -72,7 +73,7 @@ public class LoggingUtil { Block checkBlock = origin.getRelative(BlockFace.UP); if (BukkitUtils.getRelativeTopBreakabls().contains(checkBlock.getType())) { if (wcfg.isLogging(Logging.SIGNTEXT) && checkBlock.getType() == Material.SIGN_POST) { - consumer.queueSignBreak(playerName, (Sign) checkBlock.getState()); + consumer.queueSignBreak(actor, (Sign) checkBlock.getState()); } else if (checkBlock.getType() == Material.IRON_DOOR_BLOCK || checkBlock.getType() == Material.WOODEN_DOOR) { Block doorBlock = checkBlock; // If the doorBlock is the top half a door the player simply punched a door @@ -81,9 +82,9 @@ public class LoggingUtil { doorBlock = doorBlock.getRelative(BlockFace.UP); // Fall back check just in case the top half wasn't a door if (doorBlock.getType() == Material.IRON_DOOR_BLOCK || doorBlock.getType() == Material.WOODEN_DOOR) { - consumer.queueBlockBreak(playerName, doorBlock.getState()); + consumer.queueBlockBreak(actor, doorBlock.getState()); } - consumer.queueBlockBreak(playerName, checkBlock.getState()); + consumer.queueBlockBreak(actor, checkBlock.getState()); } } else if (checkBlock.getType() == Material.DOUBLE_PLANT) { Block plantBlock = checkBlock; @@ -93,12 +94,12 @@ public class LoggingUtil { plantBlock = plantBlock.getRelative(BlockFace.UP); // Fall back check just in case the top half wasn't a plant if (plantBlock.getType() == Material.DOUBLE_PLANT) { - consumer.queueBlockBreak(playerName, plantBlock.getState()); + consumer.queueBlockBreak(actor, plantBlock.getState()); } - consumer.queueBlockBreak(playerName, checkBlock.getState()); + consumer.queueBlockBreak(actor, checkBlock.getState()); } } else { - consumer.queueBlockBreak(playerName, checkBlock.getState()); + consumer.queueBlockBreak(actor, checkBlock.getState()); } } @@ -112,56 +113,56 @@ public class LoggingUtil { case REDSTONE_TORCH_ON: case REDSTONE_TORCH_OFF: if (blockState.getBlock().getRelative(((RedstoneTorch) data).getAttachedFace()).equals(origin)) { - consumer.queueBlockBreak(playerName, blockState); + consumer.queueBlockBreak(actor, blockState); } break; case TORCH: if (blockState.getBlock().getRelative(((Torch) data).getAttachedFace()).equals(origin)) { - consumer.queueBlockBreak(playerName, blockState); + consumer.queueBlockBreak(actor, blockState); } break; case COCOA: if (blockState.getBlock().getRelative(((CocoaPlant) data).getAttachedFace().getOppositeFace()).equals(origin)) { - consumer.queueBlockBreak(playerName, blockState); + consumer.queueBlockBreak(actor, blockState); } break; case LADDER: if (blockState.getBlock().getRelative(((Ladder) data).getAttachedFace()).equals(origin)) { - consumer.queueBlockBreak(playerName, blockState); + consumer.queueBlockBreak(actor, blockState); } break; case LEVER: if (blockState.getBlock().getRelative(((Lever) data).getAttachedFace()).equals(origin)) { - consumer.queueBlockBreak(playerName, blockState); + consumer.queueBlockBreak(actor, blockState); } break; case TRIPWIRE_HOOK: if (blockState.getBlock().getRelative(((TripwireHook) data).getAttachedFace()).equals(origin)) { - consumer.queueBlockBreak(playerName, blockState); + consumer.queueBlockBreak(actor, blockState); } break; case WOOD_BUTTON: case STONE_BUTTON: if (blockState.getBlock().getRelative(((Button) data).getAttachedFace()).equals(origin)) { - consumer.queueBlockBreak(playerName, blockState); + consumer.queueBlockBreak(actor, blockState); } break; case WALL_SIGN: if (blockState.getBlock().getRelative(((org.bukkit.material.Sign) data).getAttachedFace()).equals(origin)) { if (wcfg.isLogging(Logging.SIGNTEXT)) { - consumer.queueSignBreak(playerName, (Sign) blockState); + consumer.queueSignBreak(actor, (Sign) blockState); } else { - consumer.queueBlockBreak(playerName, blockState); + consumer.queueBlockBreak(actor, blockState); } } break; case TRAP_DOOR: if (blockState.getBlock().getRelative(((TrapDoor) data).getAttachedFace()).equals(origin)) { - consumer.queueBlockBreak(playerName, blockState); + consumer.queueBlockBreak(actor, blockState); } break; default: - consumer.queueBlockBreak(playerName, blockState); + consumer.queueBlockBreak(actor, blockState); break; } } @@ -179,7 +180,7 @@ public class LoggingUtil { } if (doorBlock.getType() == Material.IRON_DOOR_BLOCK || doorBlock.getType() == Material.WOODEN_DOOR) { - consumer.queueBlockBreak(playerName, doorBlock.getState()); + consumer.queueBlockBreak(actor, doorBlock.getState()); } } else if (origin.getType() == Material.DOUBLE_PLANT) { // Special double plant check Block plantBlock = origin; @@ -192,11 +193,11 @@ public class LoggingUtil { } if (plantBlock.getType() == Material.DOUBLE_PLANT) { - consumer.queueBlockBreak(playerName, plantBlock.getState()); + consumer.queueBlockBreak(actor, plantBlock.getState()); } } // Do this down here so that the block is added after blocks sitting on it - consumer.queueBlockBreak(playerName, origin.getState()); + consumer.queueBlockBreak(actor, origin.getState()); } } diff --git a/src/main/java/de/diddiz/util/UUIDFetcher.java b/src/main/java/de/diddiz/util/UUIDFetcher.java new file mode 100644 index 0000000..a699c95 --- /dev/null +++ b/src/main/java/de/diddiz/util/UUIDFetcher.java @@ -0,0 +1,79 @@ +package de.diddiz.util; + +import org.json.simple.JSONArray; +import org.json.simple.JSONObject; +import org.json.simple.parser.JSONParser; + +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.UUID; + +// Adapted from https://gist.github.com/evilmidget38/26d70114b834f71fb3b4 + +public class UUIDFetcher { + + private static final String PROFILE_URL = "https://api.mojang.com/profiles/minecraft"; + private static final JSONParser jsonParser = new JSONParser(); + + public static Map getUUIDs(List names) throws Exception { + Map uuidMap = new HashMap(); + HttpURLConnection connection = createConnection(); + String body = JSONArray.toJSONString(names); + writeBody(connection, body); + JSONArray array = (JSONArray) jsonParser.parse(new InputStreamReader(connection.getInputStream())); + for (Object profile : array) { + JSONObject jsonProfile = (JSONObject) profile; + String id = (String) jsonProfile.get("id"); + String name = (String) jsonProfile.get("name"); + UUID uuid = UUIDFetcher.getUUID(id); + uuidMap.put(name, uuid); + } + return uuidMap; + } + + private static void writeBody(HttpURLConnection connection, String body) throws Exception { + OutputStream stream = connection.getOutputStream(); + stream.write(body.getBytes()); + stream.flush(); + stream.close(); + } + + private static HttpURLConnection createConnection() throws Exception { + URL url = new URL(PROFILE_URL); + HttpURLConnection connection = (HttpURLConnection) url.openConnection(); + connection.setRequestMethod("POST"); + connection.setRequestProperty("Content-Type", "application/json"); + connection.setUseCaches(false); + connection.setDoInput(true); + connection.setDoOutput(true); + return connection; + } + + private static UUID getUUID(String id) { + return UUID.fromString(id.substring(0, 8) + "-" + id.substring(8, 12) + "-" + id.substring(12, 16) + "-" + id.substring(16, 20) + "-" + id.substring(20, 32)); + } + + public static byte[] toBytes(UUID uuid) { + ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[16]); + byteBuffer.putLong(uuid.getMostSignificantBits()); + byteBuffer.putLong(uuid.getLeastSignificantBits()); + return byteBuffer.array(); + } + + public static UUID fromBytes(byte[] array) { + if (array.length != 16) { + throw new IllegalArgumentException("Illegal byte array length: " + array.length); + } + ByteBuffer byteBuffer = ByteBuffer.wrap(array); + long mostSignificant = byteBuffer.getLong(); + long leastSignificant = byteBuffer.getLong(); + return new UUID(mostSignificant, leastSignificant); + } + +} diff --git a/src/main/java/de/diddiz/worldedit/LogBlockEditSession.java b/src/main/java/de/diddiz/worldedit/LogBlockEditSession.java index f87c786..ecd4156 100644 --- a/src/main/java/de/diddiz/worldedit/LogBlockEditSession.java +++ b/src/main/java/de/diddiz/worldedit/LogBlockEditSession.java @@ -57,7 +57,7 @@ public class LogBlockEditSession extends EditSession { // Check to see if we've broken a sign if (Config.isLogging(location.getWorld().getName(), Logging.SIGNTEXT) && (typeBefore == Material.SIGN_POST.getId() || typeBefore == Material.SIGN.getId())) { - plugin.getConsumer().queueSignBreak(player.getName(), (Sign) stateBefore); + plugin.getConsumer().queueSignBreak(player, (Sign) stateBefore); if (block.getType() != Material.AIR.getId()) { plugin.getConsumer().queueBlockPlace(player.getName(), location, block.getType(), (byte) block.getData()); } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index dce6cb3..665ae0c 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: ${project.name} -version: '1.81' +version: '1.9' author: DiddiZ authors: [md_5, ammar2, frymaster] website: http://dev.bukkit.org/server-mods/logblock/ From 050a17506abb4815f4d82ff41ae4470d7f6f9fc9 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Sun, 15 Feb 2015 02:48:03 +0000 Subject: [PATCH 31/50] UUID migrration fixes Firstly, remove incorrect unique index on playername (and UUID, just in case) columns, and add a non-unique index on the UUID column Secondly, account for setups not logging onlinetime - in that case, try to look up ALL names, and give any not found the log_ prefix rather than the noimport_ prefix --- src/main/java/de/diddiz/LogBlock/Updater.java | 49 +++++++++++++++++-- 1 file changed, 44 insertions(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 5f85a15..26e9e80 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -277,15 +277,21 @@ class Updater // Error 1060 is MySQL error "column already exists". We want to continue with import if we get that error if (ex.getErrorCode() != 1060) { Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; + return false; } } try { + String unimportedPrefix="noimport_"; ResultSet rs; conn.setAutoCommit(true); final Statement st = conn.createStatement(); - // Start by assuming anything with no onlinetime is not a player - st.execute("UPDATE `lb-players` SET UUID = CONCAT ('log_',playername) WHERE onlinetime=0 AND LENGTH(UUID) = 0"); + if (config.getBoolean("logging.logPlayerInfo")) { + // Start by assuming anything with no onlinetime is not a player + st.execute("UPDATE `lb-players` SET UUID = CONCAT ('log_',playername) WHERE onlinetime=0 AND LENGTH(UUID) = 0"); + } else { + // If we can't assume that, we must assume anything we can't look up is not a player + unimportedPrefix = "log_"; + } // Tell people how many are needing converted rs = st.executeQuery("SELECT COUNT(playername) FROM `lb-players` WHERE LENGTH(UUID)=0"); rs.next(); @@ -308,7 +314,7 @@ class Updater response = UUIDFetcher.getUUIDs(names); for (Map.Entry entry : players.entrySet()) { if (response.get(entry.getKey()) == null) { - theUUID = "noimport_" + entry.getKey(); + theUUID = unimportedPrefix + entry.getKey(); getLogger().warning(entry.getKey() + " not found - giving UUID of " + theUUID); } else { theUUID = response.get(entry.getKey()).toString(); @@ -336,6 +342,39 @@ class Updater } config.set("version", "1.90"); } + + if (config.getString("version").compareTo("1.91") < 0) { + getLogger().info("Updating tables to 1.91 ..."); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + // Need to wrap both these next two inside individual try/catch statements in case index does not exist + try { + st.execute("DROP INDEX UUID ON `lb-players`"); + } catch (final SQLException ex) { + if (ex.getErrorCode() != 1091) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + } + try { + st.execute("DROP INDEX playername ON `lb-players`"); + } catch (final SQLException ex) { + if (ex.getErrorCode() != 1091) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + } + st.execute("CREATE INDEX UUID ON `lb-players` (UUID);"); + st.close(); + conn.close(); + } catch (final SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.91"); + } logblock.saveConfig(); return true; } @@ -347,7 +386,7 @@ class Updater final Statement state = conn.createStatement(); final DatabaseMetaData dbm = conn.getMetaData(); conn.setAutoCommit(true); - createTable(dbm, state, "lb-players", "(playerid INT UNSIGNED NOT NULL AUTO_INCREMENT, UUID varchar(36) NOT NULL, playername varchar(32) NOT NULL, firstlogin DATETIME NOT NULL, lastlogin DATETIME NOT NULL, onlinetime INT UNSIGNED NOT NULL, ip varchar(255) NOT NULL, PRIMARY KEY (playerid), UNIQUE (UUID))"); + createTable(dbm, state, "lb-players", "(playerid INT UNSIGNED NOT NULL AUTO_INCREMENT, UUID varchar(36) NOT NULL, playername varchar(32) NOT NULL, firstlogin DATETIME NOT NULL, lastlogin DATETIME NOT NULL, onlinetime INT UNSIGNED NOT NULL, ip varchar(255) NOT NULL, PRIMARY KEY (playerid), INDEX (UUID))"); // Players table must not be empty or inserts won't work - bug #492 final ResultSet rs = state.executeQuery("SELECT NULL FROM `lb-players` LIMIT 1;"); if (!rs.next()) From e07038acee883077c3d2b4550c812de15b1ca020 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Sun, 15 Feb 2015 03:06:55 +0000 Subject: [PATCH 32/50] Missed version bump --- src/main/resources/plugin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 665ae0c..6fc1756 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: ${project.name} -version: '1.9' +version: '1.91' author: DiddiZ authors: [md_5, ammar2, frymaster] website: http://dev.bukkit.org/server-mods/logblock/ From b3977d3e00642324e6edcbfd64aacd19f7d80678 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Sun, 15 Feb 2015 21:59:37 +0000 Subject: [PATCH 33/50] Reduce UUID migration batch size. Fixes #576 --- src/main/java/de/diddiz/LogBlock/Updater.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 26e9e80..b4b1f16 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -30,7 +30,7 @@ import static org.bukkit.Bukkit.getLogger; class Updater { private final LogBlock logblock; - final int UUID_CONVERT_BATCH_SIZE = 100; + final int UUID_CONVERT_BATCH_SIZE = 75; Updater(LogBlock logblock) { this.logblock = logblock; From 7e4909469928405aaaacbf5b50b03285670ea87d Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Mon, 16 Feb 2015 14:13:43 +0000 Subject: [PATCH 34/50] Revert "Reduce UUID migration batch size. Fixes #576" As per https://github.com/LogBlock/LogBlock/issues/576#issuecomment-74503498 the limit is confirmed at 100 names per request. This reverts commit b3977d3e00642324e6edcbfd64aacd19f7d80678. --- src/main/java/de/diddiz/LogBlock/Updater.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index b4b1f16..26e9e80 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -30,7 +30,7 @@ import static org.bukkit.Bukkit.getLogger; class Updater { private final LogBlock logblock; - final int UUID_CONVERT_BATCH_SIZE = 75; + final int UUID_CONVERT_BATCH_SIZE = 100; Updater(LogBlock logblock) { this.logblock = logblock; From c3f5ce9a5bcd2514eb60a58baac334425dace7bc Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Mon, 16 Feb 2015 15:25:02 +0000 Subject: [PATCH 35/50] Get the UUID column when summing by players --- src/main/java/de/diddiz/LogBlock/QueryParams.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index cd07aab..e19cc4e 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -151,7 +151,7 @@ public final class QueryParams implements Cloneable } else if (sum == SummarizationMode.TYPES) return "SELECT type, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT type, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.CREATED) + "GROUP BY type) UNION (SELECT replaced AS type, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "` INNER JOIN `lb-players` USING (playerid) " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY replaced)) AS t GROUP BY type ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); else - return "SELECT playername, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "` " + getWhere(BlockChangeType.CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "` " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); + return "SELECT playername, UUID, SUM(created) AS created, SUM(destroyed) AS destroyed FROM ((SELECT playerid, count(*) AS created, 0 AS destroyed FROM `" + getTable() + "` " + getWhere(BlockChangeType.CREATED) + "GROUP BY playerid) UNION (SELECT playerid, 0 AS created, count(*) AS destroyed FROM `" + getTable() + "` " + getWhere(BlockChangeType.DESTROYED) + "GROUP BY playerid)) AS t INNER JOIN `lb-players` USING (playerid) GROUP BY playerid ORDER BY SUM(created) + SUM(destroyed) " + order + " " + getLimit(); } public String getTable() { From a9ff27a2a0bf052338420a0804a36160d86bf239 Mon Sep 17 00:00:00 2001 From: Mahagon Date: Sun, 15 Feb 2015 17:15:46 +0100 Subject: [PATCH 36/50] fireball logging did not work with 1.8 --- src/main/java/de/diddiz/LogBlock/Actor.java | 19 ++++++++++++++++--- .../LogBlock/listeners/ExplosionLogging.java | 17 ++++++++++------- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index ab12a30..1c7af16 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -1,13 +1,15 @@ package de.diddiz.LogBlock; import static de.diddiz.util.BukkitUtils.entityName; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; import java.sql.ResultSet; import java.sql.SQLException; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; +import org.bukkit.projectiles.ProjectileSource; + public class Actor { @Override @@ -69,6 +71,16 @@ public class Actor { return new Actor(entity.getName()); } + + public static Actor actorFromProjectileSource(ProjectileSource psource) { + if (psource instanceof Player) { + Player player = ((Player) psource).getPlayer(); + return new Actor(player.getName(),player.getUniqueId().toString()); + } else { + return new Actor(psource.toString()); + } + } + public static boolean isValidUUID(String uuid) { try { java.util.UUID.fromString(uuid); @@ -82,4 +94,5 @@ public class Actor { return "log_" + name; } + } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java index c2d6bac..4d9bb66 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/ExplosionLogging.java @@ -1,12 +1,9 @@ package de.diddiz.LogBlock.listeners; -import de.diddiz.LogBlock.Actor; -import de.diddiz.LogBlock.LogBlock; -import de.diddiz.LogBlock.Logging; import static de.diddiz.LogBlock.config.Config.getWorldConfig; import static de.diddiz.LogBlock.config.Config.logCreeperExplosionsAsPlayerWhoTriggeredThese; -import de.diddiz.LogBlock.config.WorldConfig; import static de.diddiz.util.BukkitUtils.getContainerBlocks; + import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; @@ -23,6 +20,12 @@ import org.bukkit.entity.minecart.ExplosiveMinecart; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.projectiles.ProjectileSource; + +import de.diddiz.LogBlock.Actor; +import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.Logging; +import de.diddiz.LogBlock.config.WorldConfig; public class ExplosionLogging extends LoggingListener { @@ -57,7 +60,7 @@ public class ExplosionLogging extends LoggingListener new Actor("Creeper"); } else if (source instanceof Fireball) { Fireball fireball = (Fireball) source; - Entity shooter = fireball.getShooter(); + ProjectileSource shooter = fireball.getShooter(); if (shooter == null) { return; } @@ -65,12 +68,12 @@ public class ExplosionLogging extends LoggingListener if (!wcfg.isLogging(Logging.GHASTFIREBALLEXPLOSION)) { return; } - actor = Actor.actorFromEntity(shooter); + actor = Actor.actorFromProjectileSource(shooter); } else if (shooter instanceof Wither) { if (!wcfg.isLogging(Logging.WITHER)) { return; } - actor = Actor.actorFromEntity(shooter); + actor = Actor.actorFromProjectileSource(shooter); } } else if (source instanceof EnderDragon) { if (!wcfg.isLogging(Logging.ENDERDRAGON)) From f46751aecdd81fca05a2d556a57ec3a6d0d08a55 Mon Sep 17 00:00:00 2001 From: Mahagon Date: Sun, 15 Feb 2015 17:44:49 +0100 Subject: [PATCH 37/50] Also log the deletion of fire by a player --- .../LogBlock/listeners/BlockBurnLogging.java | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java index 471eac4..138faa6 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java @@ -1,14 +1,20 @@ package de.diddiz.LogBlock.listeners; +import static de.diddiz.LogBlock.config.Config.isLogging; +import static de.diddiz.util.LoggingUtil.smartLogBlockBreak; +import static de.diddiz.util.LoggingUtil.smartLogFallables; + +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.EventPriority; +import org.bukkit.event.block.BlockBurnEvent; +import org.bukkit.event.player.PlayerInteractEvent; + import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; -import static de.diddiz.LogBlock.config.Config.isLogging; -import static de.diddiz.util.LoggingUtil.smartLogBlockBreak; -import static de.diddiz.util.LoggingUtil.smartLogFallables; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.block.BlockBurnEvent; public class BlockBurnLogging extends LoggingListener { @@ -23,4 +29,16 @@ public class BlockBurnLogging extends LoggingListener smartLogFallables(consumer, new Actor("Fire"), event.getBlock()); } } + + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onExtinguish(PlayerInteractEvent event) { + Player player = event.getPlayer(); + Block block = player.getTargetBlock(null, 5); + if (block.getType().equals(Material.FIRE) && isLogging(player.getWorld(), Logging.FIRE)) { + Actor actor = Actor.actorFromEntity(player); + smartLogBlockBreak(consumer, actor, block); + smartLogFallables(consumer, actor, block); + } + } } From 4effd8c9fe366a68a27d84f3860d554e957771ad Mon Sep 17 00:00:00 2001 From: Mahagon Date: Sun, 15 Feb 2015 19:06:06 +0100 Subject: [PATCH 38/50] log fire by playerinteractevent only on leftclick --- .../diddiz/LogBlock/listeners/BlockBurnLogging.java | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java index 138faa6..bb5b230 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java @@ -9,6 +9,7 @@ import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; +import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockBurnEvent; import org.bukkit.event.player.PlayerInteractEvent; @@ -35,10 +36,12 @@ public class BlockBurnLogging extends LoggingListener public void onExtinguish(PlayerInteractEvent event) { Player player = event.getPlayer(); Block block = player.getTargetBlock(null, 5); - if (block.getType().equals(Material.FIRE) && isLogging(player.getWorld(), Logging.FIRE)) { - Actor actor = Actor.actorFromEntity(player); - smartLogBlockBreak(consumer, actor, block); - smartLogFallables(consumer, actor, block); + if(event.getAction().equals(Action.LEFT_CLICK_BLOCK)){ + if (block.getType().equals(Material.FIRE) && isLogging(player.getWorld(), Logging.FIRE)) { + Actor actor = Actor.actorFromEntity(player); + smartLogBlockBreak(consumer, actor, block); + smartLogFallables(consumer, actor, block); + } } } } From a4e4c35371a501edf13c64dca23a97f19fee46cd Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Mon, 16 Feb 2015 20:09:58 +0000 Subject: [PATCH 39/50] Bukkit API version bump for projectile source --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index d83cbb7..d88a1f5 100644 --- a/pom.xml +++ b/pom.xml @@ -42,7 +42,7 @@ org.bukkit bukkit - 1.7.2-R0.1-SNAPSHOT + 1.7.2-R0.3 ${project.groupId} From be06056d5f40f548e131917a96b846d4da18064a Mon Sep 17 00:00:00 2001 From: frymaster Date: Tue, 17 Feb 2015 20:44:56 +0000 Subject: [PATCH 40/50] Corrected very broken Actor equality check --- src/main/java/de/diddiz/LogBlock/Actor.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index 1c7af16..a8311b1 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -28,10 +28,7 @@ public class Actor { return false; } final Actor other = (Actor) obj; - if ((this.UUID == null) ? (other.UUID != null) : !this.UUID.equals(other.UUID)) { - return false; - } - return true; + return ((this.UUID == null && other.UUID == null) || this.UUID.equals(other.UUID)); } final String name; @@ -71,7 +68,6 @@ public class Actor { return new Actor(entity.getName()); } - public static Actor actorFromProjectileSource(ProjectileSource psource) { if (psource instanceof Player) { Player player = ((Player) psource).getPlayer(); From 3711aa3890262e33a51ade09fe5f239cdb3f408d Mon Sep 17 00:00:00 2001 From: frymaster Date: Wed, 18 Feb 2015 21:02:35 +0000 Subject: [PATCH 41/50] Always update player name even if not logging player info. Fixes #577 --- src/main/java/de/diddiz/LogBlock/Consumer.java | 8 ++++++-- src/main/java/de/diddiz/LogBlock/LogBlock.java | 3 +-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 464d01d..a845ec4 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -670,7 +670,9 @@ public class Consumer extends TimerTask @Override public String[] getInserts() { - return new String[]{"UPDATE `lb-players` SET lastlogin = FROM_UNIXTIME(" + lastLogin + "), firstlogin = IF(firstlogin = 0, FROM_UNIXTIME(" + lastLogin + "), firstlogin), ip = '" + ip + "', playername = '" + player.getName() + "' WHERE UUID = '" + player.getUUID() + "';"}; + if (logPlayerInfo) + return new String[]{"UPDATE `lb-players` SET lastlogin = FROM_UNIXTIME(" + lastLogin + "), firstlogin = IF(firstlogin = 0, FROM_UNIXTIME(" + lastLogin + "), firstlogin), ip = '" + ip + "', playername = '" + player.getName() + "' WHERE UUID = '" + player.getUUID() + "';"}; + return new String[]{"UPDATE `lb-players` SET playername = '" + player.getName() + "' WHERE UUID = '" + player.getUUID() + "';"}; } @Override @@ -696,7 +698,9 @@ public class Consumer extends TimerTask @Override public String[] getInserts() { - return new String[]{"UPDATE `lb-players` SET onlinetime = onlinetime + TIMESTAMPDIFF(SECOND, lastlogin, FROM_UNIXTIME('" + leaveTime + "')), playername = '" + actor.getName() + "' WHERE lastlogin > 0 && UUID = '" + actor.getUUID() + "';"}; + if (logPlayerInfo) + return new String[]{"UPDATE `lb-players` SET onlinetime = onlinetime + TIMESTAMPDIFF(SECOND, lastlogin, FROM_UNIXTIME('" + leaveTime + "')), playername = '" + actor.getName() + "' WHERE lastlogin > 0 && UUID = '" + actor.getUUID() + "';"}; + return new String[]{"UPDATE `lb-players` SET playername = '" + actor.getName() + "' WHERE UUID = '" + actor.getUUID() + "';"}; } @Override diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 46b1a3b..f7d8687 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -148,6 +148,7 @@ public class LogBlock extends JavaPlugin private void registerEvents() { final PluginManager pm = getPluginManager(); pm.registerEvents(new ToolListener(this), this); + pm.registerEvents(new PlayerInfoLogging(this), this); if (askRollbackAfterBan) pm.registerEvents(new BanListener(this), this); if (isLogging(Logging.BLOCKPLACE)) @@ -190,8 +191,6 @@ public class LogBlock extends JavaPlugin pm.registerEvents(new BlockSpreadLogging(this), this); if (isLogging(Logging.LOCKEDCHESTDECAY)) pm.registerEvents(new LockedChestDecayLogging(this), this); - if (logPlayerInfo) - pm.registerEvents(new PlayerInfoLogging(this), this); } @Override From 82b4ffc2a28eef2d45713bbf5726d7c31d44e2d4 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Fri, 20 Feb 2015 22:48:40 +0000 Subject: [PATCH 42/50] Support utf8mb4 if the database does. Fixes #535 What MySQL calls "UTF8" is actually a subset of the full unicode specification. It doesn't accept 4-byte UTF-8 characters. Proper support is called "utf8mb4" and is, these days, fairly common (Ubuntu 10.04LTS's bundled MySQL does not support it, but later ones do) Detection of utf8mb4: "SHOW CHARACTER SET WHERE charset='utf8mb4';" returns at least one row Conversion of pre-existing DBs: this was easy, we already had code in the updater for this for when we started enforcing utf8. It was version-bumped and set to update to either utf8mb4 or utf8, depending Making it use utf8mb4 in the database connection: Actually hard. Connector/J 5.1.13 or newer should autodetect this, but in my testing it didn't (http://dev.mysql.com/doc/relnotes/connector-j/en/news-5-1-13.html) As such, if utf8mb4 has been detected, I've added code that should manually execute "SET NAMES utf8mb4;" on all new connections. If a database does not support utf8mb4 (rare these days) I've added code to strip these characters before DB insertion; they won't be recorded correctly, but it'll avoid the exception from issue #535 --- .../java/de/diddiz/LogBlock/BlockChange.java | 3 +- .../java/de/diddiz/LogBlock/ChatMessage.java | 3 +- .../java/de/diddiz/LogBlock/LogBlock.java | 7 ++ src/main/java/de/diddiz/LogBlock/Updater.java | 76 ++++++++++--------- .../de/diddiz/LogBlock/config/Config.java | 2 + src/main/java/de/diddiz/util/LoggingUtil.java | 7 ++ .../de/diddiz/util/MySQLConnectionPool.java | 2 + src/main/resources/plugin.yml | 2 +- 8 files changed, 62 insertions(+), 40 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/BlockChange.java b/src/main/java/de/diddiz/LogBlock/BlockChange.java index 6e823a0..493e52d 100644 --- a/src/main/java/de/diddiz/LogBlock/BlockChange.java +++ b/src/main/java/de/diddiz/LogBlock/BlockChange.java @@ -8,6 +8,7 @@ import de.diddiz.util.BukkitUtils; import org.bukkit.Location; import de.diddiz.LogBlock.config.Config; +import static de.diddiz.util.LoggingUtil.checkText; import org.bukkit.Material; public class BlockChange implements LookupCacheElement @@ -29,7 +30,7 @@ public class BlockChange implements LookupCacheElement this.replaced = replaced; this.type = type; this.data = data; - this.signtext = signtext; + this.signtext = checkText(signtext); this.ca = ca; this.playerName = actor == null ? null : actor.getName(); } diff --git a/src/main/java/de/diddiz/LogBlock/ChatMessage.java b/src/main/java/de/diddiz/LogBlock/ChatMessage.java index a060317..ec5920e 100644 --- a/src/main/java/de/diddiz/LogBlock/ChatMessage.java +++ b/src/main/java/de/diddiz/LogBlock/ChatMessage.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock; +import static de.diddiz.util.LoggingUtil.checkText; import java.sql.ResultSet; import java.sql.SQLException; import org.bukkit.Location; @@ -14,7 +15,7 @@ public class ChatMessage implements LookupCacheElement id = 0; date = System.currentTimeMillis() / 1000; this.player = player; - this.message = message; + this.message = checkText(message); this.playerName = player == null ? null : player.getName(); } diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index f7d8687..322eeb1 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -86,6 +86,13 @@ public class LogBlock extends JavaPlugin noDb = true; return; } + final Statement st = conn.createStatement(); + final ResultSet rs = st.executeQuery("SHOW CHARACTER SET where charset='utf8mb4';"); + if (rs.next()) { + Config.mb4=true; + // Allegedly JDBC driver since 2010 hasn't needed this. I did. + st.executeQuery("SET NAMES utf8mb4;"); + } conn.close(); if (updater.update()) load(this); diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 26e9e80..5fadc84 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -1,5 +1,6 @@ package de.diddiz.LogBlock; +import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.WorldConfig; import org.bukkit.Bukkit; import org.bukkit.configuration.ConfigurationSection; @@ -208,42 +209,6 @@ class Updater } config.set("version", "1.52"); } - // Ensure charset for free-text fields is UTF-8 - // As this may be an expensive operation and the database default may already be UTF-8, check on a table-by-table basis before converting - if (config.getString("version").compareTo("1.71") < 0) { - getLogger().info("Updating tables to 1.71 ..."); - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - if (isLogging(Logging.CHAT)) { - final ResultSet rs = st.executeQuery("SHOW FULL COLUMNS FROM `lb-chat` WHERE field = 'message'"); - if (rs.next() && !rs.getString("Collation").substring(0,4).equalsIgnoreCase("utf8")) { - st.execute("ALTER TABLE `lb-chat` CONVERT TO CHARSET utf8"); - getLogger().info("Table lb-chat modified"); - } else { - getLogger().info("Table lb-chat already fine, skipping it"); - } - } - for (final WorldConfig wcfg : getLoggedWorlds()) { - if (wcfg.isLogging(Logging.SIGNTEXT)) { - final ResultSet rs = st.executeQuery("SHOW FULL COLUMNS FROM `"+wcfg.table+"-sign` WHERE field = 'signtext'"); - if (rs.next() && !rs.getString("Collation").substring(0,4).equalsIgnoreCase("utf8")) { - st.execute("ALTER TABLE `"+wcfg.table+"-sign` CONVERT TO CHARSET utf8"); - getLogger().info("Table "+wcfg.table+"-sign modified"); - } else { - getLogger().info("Table "+wcfg.table+"-sign already fine, skipping it"); - } - } - } - st.close(); - conn.close(); - } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - config.set("version", "1.71"); - } if (config.getString("version").compareTo("1.81") < 0) { getLogger().info("Updating tables to 1.81 ..."); final Connection conn = logblock.getConnection(); @@ -342,7 +307,6 @@ class Updater } config.set("version", "1.90"); } - if (config.getString("version").compareTo("1.91") < 0) { getLogger().info("Updating tables to 1.91 ..."); final Connection conn = logblock.getConnection(); @@ -375,6 +339,44 @@ class Updater } config.set("version", "1.91"); } + // Ensure charset for free-text fields is UTF-8, or UTF8-mb4 if possible + // As this may be an expensive operation and the database default may already be this, check on a table-by-table basis before converting + if (config.getString("version").compareTo("1.92") < 0) { + getLogger().info("Updating tables to 1.92 ..."); + String charset = "utf8"; + if ( Config.mb4) charset="utf8mb4"; + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + if (isLogging(Logging.CHAT)) { + final ResultSet rs = st.executeQuery("SHOW FULL COLUMNS FROM `lb-chat` WHERE field = 'message'"); + if (rs.next() && !rs.getString("Collation").substring(0,4).equalsIgnoreCase(charset)) { + st.execute("ALTER TABLE `lb-chat` CONVERT TO CHARSET " + charset); + getLogger().info("Table lb-chat modified"); + } else { + getLogger().info("Table lb-chat already fine, skipping it"); + } + } + for (final WorldConfig wcfg : getLoggedWorlds()) { + if (wcfg.isLogging(Logging.SIGNTEXT)) { + final ResultSet rs = st.executeQuery("SHOW FULL COLUMNS FROM `"+wcfg.table+"-sign` WHERE field = 'signtext'"); + if (rs.next() && !rs.getString("Collation").substring(0,4).equalsIgnoreCase(charset)) { + st.execute("ALTER TABLE `"+wcfg.table+"-sign` CONVERT TO CHARSET " + charset); + getLogger().info("Table "+wcfg.table+"-sign modified"); + } else { + getLogger().info("Table "+wcfg.table+"-sign already fine, skipping it"); + } + } + } + st.close(); + conn.close(); + } catch (final SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.92"); + } logblock.saveConfig(); return true; } diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index ff78a69..88812e8 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -47,6 +47,8 @@ public class Config public static SimpleDateFormat formatter; public static boolean safetyIdCheck; public static boolean logEnvironmentalKills; + // Not loaded from config - checked at runtime + public static boolean mb4 = false; public static enum LogKillsLevel { diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index 8dca8be..0b4d67a 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -4,6 +4,7 @@ import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.Consumer; import de.diddiz.LogBlock.Logging; import static de.diddiz.LogBlock.config.Config.getWorldConfig; +import static de.diddiz.LogBlock.config.Config.mb4; import de.diddiz.LogBlock.config.WorldConfig; import java.util.List; import org.bukkit.Location; @@ -200,4 +201,10 @@ public class LoggingUtil { // Do this down here so that the block is added after blocks sitting on it consumer.queueBlockBreak(actor, origin.getState()); } + + public static String checkText(String text) { + if (text==null) return text; + if (mb4) return text; + return text.replaceAll("[^\\u0000-\\uFFFF]", "?"); + } } diff --git a/src/main/java/de/diddiz/util/MySQLConnectionPool.java b/src/main/java/de/diddiz/util/MySQLConnectionPool.java index d78af21..a986976 100644 --- a/src/main/java/de/diddiz/util/MySQLConnectionPool.java +++ b/src/main/java/de/diddiz/util/MySQLConnectionPool.java @@ -1,5 +1,6 @@ package de.diddiz.util; +import static de.diddiz.LogBlock.config.Config.mb4; import java.io.Closeable; import java.sql.Array; import java.sql.Blob; @@ -76,6 +77,7 @@ public class MySQLConnectionPool implements Closeable throw new SQLException("Failed to validate a brand new connection"); } connections.add(conn); + if (mb4) conn.createStatement().executeQuery("SET NAMES utf8mb4"); return conn; } finally { lock.unlock(); diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index 6fc1756..e143a31 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: ${project.name} -version: '1.91' +version: '1.92' author: DiddiZ authors: [md_5, ammar2, frymaster] website: http://dev.bukkit.org/server-mods/logblock/ From d48d04227933d688a462bb926bb44019fa9ba399 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Sat, 21 Feb 2015 18:20:47 +0000 Subject: [PATCH 43/50] Directly use the UUID of the player responsible for event, if possible Directly get the Bukkit World object of the event, if possible Move Worldedit World -> Bukkit World conversion to a separate method --- src/main/java/de/diddiz/LogBlock/Actor.java | 8 +++- .../worldedit/WorldEditLoggingHook.java | 39 +++++++++++++------ 2 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index ab12a30..3cbb962 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -40,6 +40,12 @@ public class Actor { this.UUID = UUID; } + + public Actor(String name, java.util.UUID UUID) { + this.name = name; + this.UUID = UUID.toString(); + + } public Actor(String name) { this(name, generateUUID(name)); @@ -59,7 +65,7 @@ public class Actor { public static Actor actorFromEntity(Entity entity) { if (entity instanceof Player) { - return new Actor(entityName(entity),entity.getUniqueId().toString()); + return new Actor(entityName(entity),entity.getUniqueId()); } else { return new Actor(entityName(entity)); } diff --git a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java index 0ecdf5a..7acc140 100644 --- a/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java +++ b/src/main/java/de/diddiz/worldedit/WorldEditLoggingHook.java @@ -4,7 +4,7 @@ import com.sk89q.worldedit.EditSession; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.entity.Player; +import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.event.extent.EditSessionEvent; //...so they ALSO have a class called Actor... need to fully-qualify when we use ours import com.sk89q.worldedit.extension.platform.Actor; @@ -13,9 +13,11 @@ import com.sk89q.worldedit.util.eventbus.Subscribe; import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.config.Config; +import java.util.logging.Level; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; @@ -31,11 +33,21 @@ public class WorldEditLoggingHook { // Convert WE Actor to LB Actor private de.diddiz.LogBlock.Actor AtoA(Actor weActor) { if (weActor.isPlayer()) { - return de.diddiz.LogBlock.Actor.actorFromEntity(plugin.getServer().getPlayer(weActor.getName())); + return new de.diddiz.LogBlock.Actor(weActor.getName(),weActor.getUniqueId()); } return new de.diddiz.LogBlock.Actor(weActor.getName()); } + private World adapt(com.sk89q.worldedit.world.World weWorld) { + if (weWorld == null) { + throw new NullPointerException("[Logblock-Worldedit] The provided world was null."); + } + if (weWorld instanceof BukkitWorld) return ((BukkitWorld) weWorld).getWorld(); + World world = Bukkit.getServer().getWorld(weWorld.getName()); + if (world == null) throw new IllegalArgumentException("Can't find a Bukkit world for " + weWorld); + return world; + } + public void hook() { WorldEdit.getInstance().getEventBus().register(new Object() { @Subscribe @@ -45,17 +57,21 @@ public class WorldEditLoggingHook { final de.diddiz.LogBlock.Actor lbActor = AtoA(actor); // Check to ensure the world should be logged - String worldName = event.getWorld().getName(); + final World world; + final com.sk89q.worldedit.world.World k = event.getWorld(); + try { + world = adapt(k); + } catch (RuntimeException ex) { + plugin.getLogger().warning("Failed to register logging for WorldEdit!"); + plugin.getLogger().log(Level.WARNING, ex.getMessage(),ex); + return; + } + // If config becomes reloadable, this check should be moved - if (!(Config.isLogging(worldName, Logging.WORLDEDIT))) { + if (!(Config.isLogging(world, Logging.WORLDEDIT))) { return; } - - final org.bukkit.World bukkitWorld = Bukkit.getWorld(worldName); - if (bukkitWorld == null) { - return; - } - + event.setExtent(new AbstractLoggingExtent(event.getExtent()) { @Override protected void onBlockChange(Vector pt, BaseBlock block) { @@ -64,8 +80,7 @@ public class WorldEditLoggingHook { return; } - Location location = new Location(bukkitWorld, pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); - + Location location = new Location(world, pt.getBlockX(), pt.getBlockY(), pt.getBlockZ()); Block origin = location.getBlock(); int typeBefore = origin.getTypeId(); byte dataBefore = origin.getData(); From 8c232b59970cc959a2a3fe10cf58f2e6ece86927 Mon Sep 17 00:00:00 2001 From: Mahagon Date: Mon, 23 Feb 2015 19:22:34 +0100 Subject: [PATCH 44/50] use getClickedBlock instead of getTargetBlock --- .../java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java index bb5b230..e819b63 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java @@ -6,6 +6,7 @@ import static de.diddiz.util.LoggingUtil.smartLogFallables; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -31,12 +32,11 @@ public class BlockBurnLogging extends LoggingListener } } - @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onExtinguish(PlayerInteractEvent event) { - Player player = event.getPlayer(); - Block block = player.getTargetBlock(null, 5); if(event.getAction().equals(Action.LEFT_CLICK_BLOCK)){ + Player player = event.getPlayer(); + Block block = event.getClickedBlock().getRelative(event.getBlockFace()); if (block.getType().equals(Material.FIRE) && isLogging(player.getWorld(), Logging.FIRE)) { Actor actor = Actor.actorFromEntity(player); smartLogBlockBreak(consumer, actor, block); From 951bed37431090af1ed8809ee6a4081a47181533 Mon Sep 17 00:00:00 2001 From: Mahagon Date: Tue, 24 Feb 2015 20:07:44 +0000 Subject: [PATCH 45/50] Added new material data values --- src/main/java/de/diddiz/util/MaterialName.java | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/main/java/de/diddiz/util/MaterialName.java b/src/main/java/de/diddiz/util/MaterialName.java index 4855316..37d9b64 100644 --- a/src/main/java/de/diddiz/util/MaterialName.java +++ b/src/main/java/de/diddiz/util/MaterialName.java @@ -28,12 +28,24 @@ public class MaterialName if (cfg.getKeys(false).isEmpty()) { // Generate defaults cfg.options().header("Add block or item names you want to be overridden or also names for custom blocks"); + cfg.set("1.1", "granite"); + cfg.set("1.2", "polished granite"); + cfg.set("1.3", "diorite"); + cfg.set("1.4", "polished diorite"); + cfg.set("1.5", "andesite"); + cfg.set("1.6", "polished andesite"); + cfg.set("3.1", "coarse dirt"); + cfg.set("3.2", "podzol"); cfg.set("6.1", "redwood sapling"); cfg.set("6.2", "birch sapling"); + cfg.set("6.3", "jungle sapling"); + cfg.set("6.4", "acacia sapling"); + cfg.set("6.5", "dark oak sapling"); cfg.set("9", "water"); cfg.set("11", "lava"); cfg.set("17.1", "redwood log"); cfg.set("17.2", "birch log"); + cfg.set("17.3", "jungle log"); cfg.set("18.1", "redwood leaves"); cfg.set("18.2", "birch leaves"); cfg.set("31.0", "dead long grass"); From 32c5e16de63e71bda7d1b04f05c15bd930a54f9b Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Tue, 24 Feb 2015 22:52:14 +0000 Subject: [PATCH 46/50] - Massively expand the friendly names for data values - Print warning if the pre-existing file doesn't contain one of the new names - Make name lookup in plugin startup to force the MaterialName static code to be run --- .../java/de/diddiz/LogBlock/LogBlock.java | 2 + .../java/de/diddiz/util/MaterialName.java | 145 +++++++++++++++++- 2 files changed, 140 insertions(+), 7 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 384f3ab..b28aed7 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -45,6 +45,7 @@ import java.util.Timer; import java.util.logging.Level; import static de.diddiz.LogBlock.config.Config.*; +import static de.diddiz.util.MaterialName.materialName; import static org.bukkit.Bukkit.getPluginManager; public class LogBlock extends JavaPlugin @@ -109,6 +110,7 @@ public class LogBlock extends JavaPlugin @Override public void onEnable() { + materialName(0); // Force static code to run final PluginManager pm = getPluginManager(); if (errorAtLoading) { pm.disablePlugin(this); diff --git a/src/main/java/de/diddiz/util/MaterialName.java b/src/main/java/de/diddiz/util/MaterialName.java index 37d9b64..4213c38 100644 --- a/src/main/java/de/diddiz/util/MaterialName.java +++ b/src/main/java/de/diddiz/util/MaterialName.java @@ -15,6 +15,7 @@ import org.bukkit.material.MaterialData; public class MaterialName { + private static final String[] COLORS = {"white","orange","magenta","light blue","yellow","lime","pink","gray","silver","cyan","purple","blue","brown","green","red","black"}; private static final Map materialNames = new HashMap(); private static final Map> materialDataNames = new HashMap>(); @@ -34,6 +35,12 @@ public class MaterialName cfg.set("1.4", "polished diorite"); cfg.set("1.5", "andesite"); cfg.set("1.6", "polished andesite"); + cfg.set("5.0", "oak wood"); + cfg.set("5.1", "spruce wood"); + cfg.set("5.2", "birch wood"); + cfg.set("5.3", "jungle wood"); + cfg.set("5.4", "acacia wood"); + cfg.set("5.5", "dark oak wood"); cfg.set("3.1", "coarse dirt"); cfg.set("3.2", "podzol"); cfg.set("6.1", "redwood sapling"); @@ -43,20 +50,140 @@ public class MaterialName cfg.set("6.5", "dark oak sapling"); cfg.set("9", "water"); cfg.set("11", "lava"); - cfg.set("17.1", "redwood log"); + cfg.set("12.1", "red sand"); + cfg.set("17.0", "oak log"); + cfg.set("17.1", "spruce log"); cfg.set("17.2", "birch log"); cfg.set("17.3", "jungle log"); - cfg.set("18.1", "redwood leaves"); + cfg.set("17.4", "oak log"); + cfg.set("17.5", "spruce log"); + cfg.set("17.6", "birch log"); + cfg.set("17.7", "jungle log"); + cfg.set("17.8", "oak log"); + cfg.set("17.9", "spruce log"); + cfg.set("17.10", "birch log"); + cfg.set("17.11", "jungle log"); + cfg.set("17.12", "oak log"); + cfg.set("17.13", "spruce log"); + cfg.set("17.14", "birch log"); + cfg.set("17.15", "jungle log"); + cfg.set("18.1", "spruce leaves"); cfg.set("18.2", "birch leaves"); - cfg.set("31.0", "dead long grass"); + cfg.set("18.3", "jungle leaves"); + cfg.set("18.4", "oak leaves"); + cfg.set("18.5", "spruce leaves"); + cfg.set("18.6", "birch leaves"); + cfg.set("18.7", "jungle leaves"); + cfg.set("18.8", "oak leaves"); + cfg.set("18.9", "spruce leaves"); + cfg.set("18.10", "birch leaves"); + cfg.set("18.11", "jungle leaves"); + cfg.set("18.12", "oak leaves"); + cfg.set("18.13", "spruce leaves"); + cfg.set("18.14", "birch leaves"); + cfg.set("18.15", "jungle leaves"); + cfg.set("19.1", "wet sponge"); + cfg.set("37.0", "dandelion"); + cfg.set("38.0", "poppy"); + cfg.set("38.1", "blue orchid"); + cfg.set("38.2", "allium"); + cfg.set("38.3", "azure bluet"); + cfg.set("38.4", "red tulip"); + cfg.set("38.5", "orange tulip"); + cfg.set("38.6", "white tulip"); + cfg.set("38.7", "pink tulip"); + cfg.set("38.8", "oxeye daisy"); + cfg.set("24.1", "chiseled sandstone"); + cfg.set("24.2", "smooth sandstone"); + cfg.set("31.0", "dead bush"); + cfg.set("31.1", "tall grass"); cfg.set("31.2", "fern"); - for (byte i = 0; i < 7; i++) { - cfg.set("35." + i, toReadable(Material.STEP.getNewData(i))); - cfg.set("351." + i, toReadable(Material.DOUBLE_STEP.getNewData(i))); + cfg.set("98.0", "stone brick"); + cfg.set("98.1", "mossy stone brick"); + cfg.set("98.2", "cracked stone brick"); + cfg.set("98.3", "chiseled stone brick"); + cfg.set("125.0","oak double step"); + cfg.set("125.1","spruce double step"); + cfg.set("125.2","birch double step"); + cfg.set("125.3","jungle double step"); + cfg.set("125.4","acacia double step"); + cfg.set("125.5","dark oak double step"); + cfg.set("126.0", "oak step"); + cfg.set("126.1", "spruce step"); + cfg.set("126.2", "birch step"); + cfg.set("126.3", "jungle step"); + cfg.set("126.4", "acacia step"); + cfg.set("126.5", "dark oak step"); + cfg.set("126.8", "oak step"); + cfg.set("126.9", "spruce step"); + cfg.set("126.10", "birch step"); + cfg.set("126.11", "jungle step"); + cfg.set("126.12", "acacia step"); + cfg.set("126.13", "dark oak step"); + cfg.set("139.1", "mossy cobble wall"); + cfg.set("155.1", "chiseled quartz block"); + cfg.set("155.2", "pillar quartz block"); + cfg.set("155.3", "pillar quartz block"); + cfg.set("155.4", "pillar quartz block"); + cfg.set("161.0", "acacia leaves"); + cfg.set("161.1", "dark oak leaves"); + cfg.set("161.4", "acacia leaves"); + cfg.set("161.5", "dark oak leaves"); + cfg.set("161.8", "acacia leaves"); + cfg.set("161.9", "dark oak leaves"); + cfg.set("161.12", "acacia leaves"); + cfg.set("161.13", "dark oak leaves"); + cfg.set("162.0", "acacia log"); + cfg.set("162.1", "dark oak log"); + cfg.set("162.4", "acacia log"); + cfg.set("162.5", "dark oak log"); + cfg.set("162.8", "acacia log"); + cfg.set("162.9", "dark oak log"); + cfg.set("162.12", "acacia log"); + cfg.set("162.13", "dark oak log"); + cfg.set("168.1", "prismarine bricks"); + cfg.set("168.2", "dark prismarine"); + cfg.set("181.0", "red sandstone double step"); + cfg.set("181.8", "smooth red sandstone double step"); + cfg.set("162.13", "dark oak log"); + cfg.set("175.0", "sunflower"); + cfg.set("175.1", "lilac"); + cfg.set("175.2", "double tall grass"); + cfg.set("175.3", "large fern"); + cfg.set("175.4", "rose bush"); + cfg.set("175.5", "peony"); + cfg.set("175.8", "sunflower"); + cfg.set("175.9", "lilac"); + cfg.set("175.10", "double tall grass"); + cfg.set("175.11", "large fern"); + cfg.set("175.12", "rose bush"); + cfg.set("175.13", "peony"); + cfg.set("179.1", "chiseled sandstone"); + cfg.set("179.2", "smooth sandstone"); + cfg.set("263.1", "charcoal"); + for (byte i = 0; i < 10; i++) { + cfg.set("43." + i, toReadable(Material.DOUBLE_STEP.getNewData(i))); + } + cfg.set("43.8", "stone double step"); + cfg.set("43.9", "sandstone double step"); + cfg.set("43.15", "quartz double step"); + for (byte i = 0; i < 8; i++) { + cfg.set("44." + i, toReadable(Material.STEP.getNewData(i))); + // The second half of this data list should read the same as the first half + cfg.set("44." + (i+7), toReadable(Material.STEP.getNewData(i))); } for (byte i = 0; i < 16; i++) { - cfg.set("35." + i, toReadable(Material.WOOL.getNewData(i))); cfg.set("351." + i, toReadable(Material.INK_SACK.getNewData(i))); + cfg.set("35." + i, COLORS[i] + " wool"); + cfg.set("159." + i, COLORS[i] + " stained clay"); + cfg.set("95." + i, COLORS[i] + " stained glass"); + cfg.set("160." + i, COLORS[i] + " stained glass pane"); + cfg.set("171." + i, COLORS[i] + " carpet"); + } + for (byte i = 0; i < 6; i++) { + cfg.set("125." + i, toReadable(Material.WOOD_DOUBLE_STEP.getNewData(i))); + cfg.set("126." + i, toReadable(Material.WOOD_STEP.getNewData(i))); + cfg.set("126." + i+8, toReadable(Material.WOOD_STEP.getNewData(i))); } try { cfg.save(file); @@ -64,6 +191,10 @@ public class MaterialName getLogger().log(Level.WARNING, "Unable to save material.yml: ", ex); } } + if (cfg.getString("263.1") == null) { + getLogger().info("[Logblock-names] Logblock's default materials.yml file has been updated with more names"); + getLogger().info("[Logblock-names] Consider deleting your current materials.yml file to allow it to be recreated"); + } for (final String entry : cfg.getKeys(false)) if (isInt(entry)) { if (cfg.isString(entry)) From 1cb32d26ed614e14c7844922397274112bb8d985 Mon Sep 17 00:00:00 2001 From: Mahagon Date: Mon, 23 Feb 2015 23:52:42 +0100 Subject: [PATCH 47/50] Check if WorldEdit Version is above WE 5 --- src/main/java/de/diddiz/LogBlock/LogBlock.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index b28aed7..6b3d809 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -119,7 +119,11 @@ public class LogBlock extends JavaPlugin if (noDb) return; if (pm.getPlugin("WorldEdit") != null) { - new WorldEditLoggingHook(this).hook(); + if(Integer.parseInt(pm.getPlugin("WorldEdit").getDescription().getVersion().substring(0, 1)) > 5) { + new WorldEditLoggingHook(this).hook(); + } else { + getLogger().warning("Failed to hook into WorldEdit. Your WorldEdit version seems to be outdated, please make sure WorldEdit is at least version 6."); + } } commandsHandler = new CommandsHandler(this); getCommand("lb").setExecutor(commandsHandler); From df8bc51437bf0023dc1b8fe31a50daeb653ad2fb Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Thu, 26 Feb 2015 16:44:46 +0000 Subject: [PATCH 48/50] Use custom names in block lookups Currently will search only using block type ie searching for prismarine_brick will search for all prismarine blocks Also removed pluralisation of prismarine_brick --- .../java/de/diddiz/LogBlock/QueryParams.java | 5 ++-- .../java/de/diddiz/util/MaterialName.java | 23 ++++++++++++++++--- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/QueryParams.java b/src/main/java/de/diddiz/LogBlock/QueryParams.java index e19cc4e..0c2cb29 100644 --- a/src/main/java/de/diddiz/LogBlock/QueryParams.java +++ b/src/main/java/de/diddiz/LogBlock/QueryParams.java @@ -20,6 +20,7 @@ import static de.diddiz.LogBlock.config.Config.*; import static de.diddiz.util.BukkitUtils.friendlyWorldname; import static de.diddiz.util.BukkitUtils.getBlockEquivalents; import static de.diddiz.util.MaterialName.materialName; +import static de.diddiz.util.MaterialName.typeFromName; import static de.diddiz.util.Utils.*; public final class QueryParams implements Cloneable @@ -579,9 +580,7 @@ public final class QueryParams implements Cloneable types.add(new Block(mat.getId(), data)); } else { final Material mat = Material.matchMaterial(blockName); - if (mat == null) - throw new IllegalArgumentException("No material matching: '" + blockName + "'"); - types.add(new Block(mat.getId(), -1)); + types.add(new Block(typeFromName(blockName), -1)); } } } else if (param.equals("area")) { diff --git a/src/main/java/de/diddiz/util/MaterialName.java b/src/main/java/de/diddiz/util/MaterialName.java index 4213c38..2be9310 100644 --- a/src/main/java/de/diddiz/util/MaterialName.java +++ b/src/main/java/de/diddiz/util/MaterialName.java @@ -18,6 +18,7 @@ public class MaterialName private static final String[] COLORS = {"white","orange","magenta","light blue","yellow","lime","pink","gray","silver","cyan","purple","blue","brown","green","red","black"}; private static final Map materialNames = new HashMap(); private static final Map> materialDataNames = new HashMap>(); + private static final Map nameTypes = new HashMap(); static { // Add all known materials @@ -141,7 +142,7 @@ public class MaterialName cfg.set("162.9", "dark oak log"); cfg.set("162.12", "acacia log"); cfg.set("162.13", "dark oak log"); - cfg.set("168.1", "prismarine bricks"); + cfg.set("168.1", "prismarine brick"); cfg.set("168.2", "dark prismarine"); cfg.set("181.0", "red sandstone double step"); cfg.set("181.8", "smooth red sandstone double step"); @@ -197,16 +198,20 @@ public class MaterialName } for (final String entry : cfg.getKeys(false)) if (isInt(entry)) { - if (cfg.isString(entry)) + if (cfg.isString(entry)) { materialNames.put(Integer.valueOf(entry), cfg.getString(entry)); + nameTypes.put(cfg.getString(entry), Integer.valueOf(entry)); + } else if (cfg.isConfigurationSection(entry)) { final Map dataNames = new HashMap(); materialDataNames.put(Integer.valueOf(entry), dataNames); final ConfigurationSection sec = cfg.getConfigurationSection(entry); for (final String data : sec.getKeys(false)) if (isShort(data)) { - if (sec.isString(data)) + if (sec.isString(data)) { dataNames.put(Short.valueOf(data), sec.getString(data)); + nameTypes.put(sec.getString(data), Integer.valueOf(entry)); + } else getLogger().warning("Parsing materials.yml: '" + data + "' is not a string."); } else @@ -234,8 +239,20 @@ public class MaterialName return dataNames.get(data); return materialName(type); } + + public static Integer typeFromName(String name) { + Integer answer = nameTypes.get(toReadable(name)); + if (answer != null) return answer; + final Material mat = Material.matchMaterial(name); + if (mat == null) throw new IllegalArgumentException("No material matching: '" + name + "'"); + return mat.getId(); + } private static String toReadable(MaterialData matData) { return matData.toString().toLowerCase().replace('_', ' ').replaceAll("[^a-z ]", ""); } + + private static String toReadable(String matData) { + return matData.toLowerCase().replace('_', ' ').replaceAll("[^a-z ]", ""); + } } From 143bcf6d762dca955e614c9d38f84a8d0177b62b Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Sat, 28 Feb 2015 12:12:27 +0000 Subject: [PATCH 49/50] Add missing index on playername column --- src/main/java/de/diddiz/LogBlock/Updater.java | 66 ++++++++++--------- src/main/resources/plugin.yml | 2 +- 2 files changed, 35 insertions(+), 33 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Updater.java b/src/main/java/de/diddiz/LogBlock/Updater.java index 5fadc84..ea4aa18 100644 --- a/src/main/java/de/diddiz/LogBlock/Updater.java +++ b/src/main/java/de/diddiz/LogBlock/Updater.java @@ -306,38 +306,6 @@ class Updater return false; } config.set("version", "1.90"); - } - if (config.getString("version").compareTo("1.91") < 0) { - getLogger().info("Updating tables to 1.91 ..."); - final Connection conn = logblock.getConnection(); - try { - conn.setAutoCommit(true); - final Statement st = conn.createStatement(); - // Need to wrap both these next two inside individual try/catch statements in case index does not exist - try { - st.execute("DROP INDEX UUID ON `lb-players`"); - } catch (final SQLException ex) { - if (ex.getErrorCode() != 1091) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - } - try { - st.execute("DROP INDEX playername ON `lb-players`"); - } catch (final SQLException ex) { - if (ex.getErrorCode() != 1091) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - } - st.execute("CREATE INDEX UUID ON `lb-players` (UUID);"); - st.close(); - conn.close(); - } catch (final SQLException ex) { - Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); - return false; - } - config.set("version", "1.91"); } // Ensure charset for free-text fields is UTF-8, or UTF8-mb4 if possible // As this may be an expensive operation and the database default may already be this, check on a table-by-table basis before converting @@ -377,6 +345,40 @@ class Updater } config.set("version", "1.92"); } + if (config.getString("version").compareTo("1.93") < 0) { + getLogger().info("Updating tables to 1.93 ..."); + final Connection conn = logblock.getConnection(); + try { + conn.setAutoCommit(true); + final Statement st = conn.createStatement(); + // Need to wrap both these next two inside individual try/catch statements in case index does not exist + try { + st.execute("DROP INDEX UUID ON `lb-players`"); + } catch (final SQLException ex) { + if (ex.getErrorCode() != 1091) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + } + try { + st.execute("DROP INDEX playername ON `lb-players`"); + } catch (final SQLException ex) { + if (ex.getErrorCode() != 1091) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + } + st.execute("CREATE INDEX UUID ON `lb-players` (UUID);"); + st.execute("CREATE INDEX playername ON `lb-players` (playername);"); + st.close(); + conn.close(); + } catch (final SQLException ex) { + Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex); + return false; + } + config.set("version", "1.93"); + } + logblock.saveConfig(); return true; } diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index e143a31..cb3d5ca 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: ${project.name} -version: '1.92' +version: '1.93' author: DiddiZ authors: [md_5, ammar2, frymaster] website: http://dev.bukkit.org/server-mods/logblock/ From 6a38708a3218745042703d36a8f765ae5fb1f238 Mon Sep 17 00:00:00 2001 From: Philip Cass Date: Sun, 22 Feb 2015 10:45:37 +0000 Subject: [PATCH 50/50] Merge identically-formed db INSERT rows into a single batch statement This increases insert speed by up to 6 times when the DB server is on the same box as the minecraft server, and many HUNDREDS of times when it is accessed via a network connection. This creates a new kind of BlockRow which is a collection of many similar rows, each of which uses the same PreparedStatement. As such, when asked to run, it can use the executeBatch() method. It also adds code to BlockRow to see if they are mergeable (it won't if they have sign or chest actions associated) and to merge two rows into one of these new objects. The consumer processing loop is altered to check for merges, and do so if possible. Also, prevent consumer race condition on shutdown On shutdown, LogBlock invokes the consumer's run() method up to twn times on the main thread. However, the consumer may still be running from the last scheduled task, and this could result in two threads running the run() code simultaneously, resulting in inconsistent row insertion order. Another scenario is that the consumer has just started processing the last row in the queue. With the queue empty, the server will terminate, but the consumer could still not have fully executed the databse query. To solve this, the run() method is syncronized, so it can only be run on the object by one thread at a time, and is made to run at least once (to force LB to wait on any already processing run) Also, the pause between consumer runs was altered to be in ticks (50ms) rather than in seconds, to prevent needless pauses between runs. Fixes #580 Fixes #56 --- .../java/de/diddiz/LogBlock/Consumer.java | 142 +++++++++++++++++- .../java/de/diddiz/LogBlock/LogBlock.java | 11 +- .../de/diddiz/LogBlock/config/Config.java | 2 +- 3 files changed, 146 insertions(+), 9 deletions(-) diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index a845ec4..3a7c9cb 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -268,7 +268,7 @@ public class Consumer extends TimerTask } @Override - public void run() { + public synchronized void run() { if (queue.isEmpty() || !lock.tryLock()) return; final Connection conn = logblock.getConnection(); @@ -302,6 +302,24 @@ public class Consumer extends TimerTask } if (r instanceof PreparedStatementRow) { PreparedStatementRow PSRow = (PreparedStatementRow) r; + if (r instanceof MergeableRow) { + int batchCount=count; + // if we've reached our row target but not exceeded our time target, allow merging of up to 50% of our row limit more rows + if (count > forceToProcessAtLeast) batchCount = forceToProcessAtLeast / 2; + while(!queue.isEmpty()) { + MergeableRow mRow = (MergeableRow) PSRow; + Row s = queue.peek(); + if (s == null) break; + if (!(s instanceof MergeableRow)) break; + MergeableRow mRow2 = (MergeableRow) s; + if (mRow.canMerge(mRow2)) { + PSRow = mRow.merge((MergeableRow) queue.poll()); + count++; + batchCount++; + if (batchCount > forceToProcessAtLeast) break; + } else break; + } + } PSRow.setConnection(conn); try { PSRow.executeStatements(); @@ -446,10 +464,16 @@ public class Consumer extends TimerTask abstract void setConnection(Connection connection); abstract void executeStatements() throws SQLException; - } - private class BlockRow extends BlockChange implements PreparedStatementRow + private interface MergeableRow extends PreparedStatementRow + { + abstract boolean isUnique(); + abstract boolean canMerge(MergeableRow row); + abstract MergeableRow merge(MergeableRow second); + } + + private class BlockRow extends BlockChange implements MergeableRow { private Connection connection; @@ -554,6 +578,118 @@ public class Consumer extends TimerTask } } } + + @Override + public boolean isUnique() { + return !(signtext == null && ca == null && playerIds.containsKey(actor)); + } + + @Override + public boolean canMerge(MergeableRow row) { + return !this.isUnique() && !row.isUnique() && row instanceof BlockRow && getWorldConfig(loc.getWorld()).table.equals(getWorldConfig(((BlockRow) row).loc.getWorld()).table); + } + + @Override + public MergeableRow merge(MergeableRow singleRow) { + return new MultiBlockChangeRow(this,(BlockRow) singleRow); + } + } + + private class MultiBlockChangeRow implements MergeableRow{ + private List rows = new ArrayList(); + private Connection connection; + private Set players = new HashSet(); + private Set actors = new HashSet(); + private String table; + + MultiBlockChangeRow (BlockRow first, BlockRow second) { + if (first.isUnique() || second.isUnique()) throw new IllegalArgumentException("Can't merge a unique row"); + rows.add(first); + rows.add(second); + actors.addAll(Arrays.asList(first.getActors())); + actors.addAll(Arrays.asList(second.getActors())); + players.addAll(Arrays.asList(first.getPlayers())); + players.addAll(Arrays.asList(second.getPlayers())); + table = getWorldConfig(first.loc.getWorld()).table; + } + + @Override + public void setConnection(Connection connection) { + this.connection = connection; + } + + @Override + public void executeStatements() throws SQLException { + PreparedStatement ps = null; + try { + ps = connection.prepareStatement("INSERT INTO `" + table + "` (date, playerid, replaced, type, data, x, y, z) VALUES(FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?)"); + for (BlockRow row : rows) { + ps.setLong(1, row.date ); + ps.setInt(2, playerIds.get(row.actor)); + ps.setInt(3, row.replaced); + ps.setInt(4, row.type); + ps.setInt(5, row.data); + ps.setInt(6, row.loc.getBlockX()); + ps.setInt(7, row.loc.getBlockY()); + ps.setInt(8, row.loc.getBlockZ()); + ps.addBatch(); + } + ps.executeBatch(); + } catch (final SQLException ex) { + if (ps != null) { + getLogger().log(Level.SEVERE, "[Consumer] Troublesome query: " + ps.toString()); + } + throw ex; + } finally { + // individual try/catch here, though ugly, prevents resource leaks + if( ps != null ) { + try { + ps.close(); + } + catch(SQLException e) { + e.printStackTrace(); + } + } + } + } + + @Override + public boolean isUnique() { + return true; + } + + @Override + public boolean canMerge(MergeableRow row) { + return !row.isUnique() && row instanceof BlockRow && table.equals(getWorldConfig(((BlockRow) row).loc.getWorld()).table); + } + + @Override + public MergeableRow merge(MergeableRow second) { + if (second.isUnique()) throw new IllegalArgumentException("Can't merge a unique row"); + rows.add((BlockRow) second); + actors.addAll(Arrays.asList(second.getActors())); + players.addAll(Arrays.asList(second.getPlayers())); + return this; + } + + @Override + public String[] getInserts() { + List l = new ArrayList(); + for (BlockRow row : rows) { + l.addAll(Arrays.asList(row.getInserts())); + } + return (String[]) l.toArray(); + } + + @Override + public String[] getPlayers() { + return (String[]) players.toArray(); + } + + @Override + public Actor[] getActors() { + return (Actor[]) actors.toArray(); + } } private class KillRow implements Row diff --git a/src/main/java/de/diddiz/LogBlock/LogBlock.java b/src/main/java/de/diddiz/LogBlock/LogBlock.java index 322eeb1..fd4ca97 100644 --- a/src/main/java/de/diddiz/LogBlock/LogBlock.java +++ b/src/main/java/de/diddiz/LogBlock/LogBlock.java @@ -126,16 +126,16 @@ public class LogBlock extends JavaPlugin getServer().getScheduler().runTaskAsynchronously(this, new DumpedLogImporter(this)); registerEvents(); if (useBukkitScheduler) { - if (getServer().getScheduler().runTaskTimerAsynchronously(this, consumer, delayBetweenRuns * 20, delayBetweenRuns * 20).getTaskId() > 0) + if (getServer().getScheduler().runTaskTimerAsynchronously(this, consumer, delayBetweenRuns < 20 ? 20 : delayBetweenRuns, delayBetweenRuns).getTaskId() > 0) getLogger().info("Scheduled consumer with bukkit scheduler."); else { getLogger().warning("Failed to schedule consumer with bukkit scheduler. Now trying schedule with timer."); timer = new Timer(); - timer.scheduleAtFixedRate(consumer, delayBetweenRuns * 1000, delayBetweenRuns * 1000); + timer.schedule(consumer, delayBetweenRuns < 20 ? 1000 : delayBetweenRuns * 50, delayBetweenRuns * 50); } } else { timer = new Timer(); - timer.scheduleAtFixedRate(consumer, delayBetweenRuns * 1000, delayBetweenRuns * 1000); + timer.schedule(consumer, delayBetweenRuns < 20 ? 1000 : delayBetweenRuns * 50, delayBetweenRuns * 50); getLogger().info("Scheduled consumer with timer."); } getServer().getScheduler().runTaskAsynchronously(this, new Updater.PlayerCountChecker(this)); @@ -209,9 +209,10 @@ public class LogBlock extends JavaPlugin if (logPlayerInfo && getServer().getOnlinePlayers() != null) for (final Player player : getServer().getOnlinePlayers()) consumer.queueLeave(player); + getLogger().info("Waiting for consumer ..."); + consumer.run(); if (consumer.getQueueSize() > 0) { - getLogger().info("Waiting for consumer ..."); - int tries = 10; + int tries = 9; while (consumer.getQueueSize() > 0) { getLogger().info("Remaining queue size: " + consumer.getQueueSize()); if (tries > 0) diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 88812e8..27bca7d 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -133,7 +133,7 @@ public class Config if (!config.contains(e.getKey())) config.set(e.getKey(), e.getValue()); logblock.saveConfig(); - url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database") + "?useUnicode=true&characterEncoding=utf-8"; + url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database") + "?useUnicode=true&characterEncoding=utf-8&rewriteBatchedStatements=true"; user = getStringIncludingInts(config, "mysql.user"); password = getStringIncludingInts(config, "mysql.password"); delayBetweenRuns = config.getInt("consumer.delayBetweenRuns", 2);