diff --git a/src/main/java/de/diddiz/LogBlock/Actor.java b/src/main/java/de/diddiz/LogBlock/Actor.java index 95d0f96..f209c4b 100644 --- a/src/main/java/de/diddiz/LogBlock/Actor.java +++ b/src/main/java/de/diddiz/LogBlock/Actor.java @@ -12,6 +12,8 @@ import java.util.Collection; import static de.diddiz.util.BukkitUtils.entityName; import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.block.Block; public class Actor { @@ -36,23 +38,40 @@ public class Actor { final String name; final String UUID; + final Location blockLocation; public Actor(String name, String UUID) { this.name = name; this.UUID = UUID; + this.blockLocation = null; + } + public Actor(String name, String UUID, Block block) { + this.name = name; + this.UUID = UUID; + this.blockLocation = block == null ? null : block.getLocation(); } public Actor(String name, java.util.UUID UUID) { this.name = name; this.UUID = UUID.toString(); + this.blockLocation = null; + } + public Actor(String name, java.util.UUID UUID, Block block) { + this.name = name; + this.UUID = UUID.toString(); + this.blockLocation = block == null ? null : block.getLocation(); } public Actor(String name) { this(name, generateUUID(name)); } + public Actor(String name, Block block) { + this(name, generateUUID(name), block); + } + public Actor(ResultSet rs) throws SQLException { this(rs.getString("playername"), rs.getString("UUID")); } @@ -65,6 +84,10 @@ public class Actor { return UUID; } + public Location getBlockLocation() { + return blockLocation; + } + public static Actor actorFromEntity(Entity entity) { if (entity instanceof Player) { return new Actor(entityName(entity), entity.getUniqueId()); diff --git a/src/main/java/de/diddiz/LogBlock/Consumer.java b/src/main/java/de/diddiz/LogBlock/Consumer.java index 31e315c..02ac410 100644 --- a/src/main/java/de/diddiz/LogBlock/Consumer.java +++ b/src/main/java/de/diddiz/LogBlock/Consumer.java @@ -705,12 +705,14 @@ public class Consumer extends Thread { private class BlockRow extends BlockChange implements Row { final String statementString; + final String selectActorIdStatementString; public BlockRow(Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) { super(System.currentTimeMillis() / 1000, loc, actor, replaced, replacedData, replacedState, type, typeData, typeState, ca); final String table = getWorldConfig(loc.getWorld()).table; statementString = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"; + selectActorIdStatementString = "SELECT playerid FROM `" + table + "-blocks` WHERE x = ? AND y = ? AND z = ? ORDER BY date DESC LIMIT 1"; } @Override @@ -735,9 +737,27 @@ public class Consumer extends Thread { @Override public void process(Connection conn, BatchHelper batchHelper) throws SQLException { + int sourceActor = playerIDAsIntIncludeUncommited(actor); + Location actorBlockLocation = actor.getBlockLocation(); + if(actorBlockLocation != null) { + Integer tempSourceActor = batchHelper.getUncommitedBlockActor(actorBlockLocation); + if(tempSourceActor != null) { + sourceActor = tempSourceActor; + } else { + PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, selectActorIdStatementString, Statement.NO_GENERATED_KEYS); + smt.setInt(1, actorBlockLocation.getBlockX()); + smt.setInt(2, safeY(actorBlockLocation)); + smt.setInt(3, actorBlockLocation.getBlockZ()); + ResultSet rs = smt.executeQuery(); + if (rs.next()) { + sourceActor = rs.getInt(1); + } + rs.close(); + } + } PreparedStatement smt = batchHelper.getOrPrepareStatement(conn, statementString, Statement.RETURN_GENERATED_KEYS); smt.setLong(1, date); - smt.setInt(2, playerIDAsIntIncludeUncommited(actor)); + smt.setInt(2, sourceActor); smt.setInt(3, replacedMaterial); smt.setInt(4, replacedData); smt.setInt(5, typeMaterial); @@ -745,6 +765,7 @@ public class Consumer extends Thread { smt.setInt(7, loc.getBlockX()); smt.setInt(8, safeY(loc)); smt.setInt(9, loc.getBlockZ()); + batchHelper.addUncommitedBlockActorId(loc, sourceActor); batchHelper.addBatch(smt, new IntCallback() { @Override public void call(int id) throws SQLException { @@ -936,11 +957,21 @@ public class Consumer extends Thread { private HashMap preparedStatements = new HashMap<>(); private HashSet preparedStatementsWithGeneratedKeys = new HashSet<>(); private LinkedHashMap> generatedKeyHandler = new LinkedHashMap<>(); + private HashMap uncommitedBlockActors = new HashMap<>(); public void reset() { preparedStatements.clear(); preparedStatementsWithGeneratedKeys.clear(); generatedKeyHandler.clear(); + uncommitedBlockActors.clear(); + } + + public void addUncommitedBlockActorId(Location loc, int actorId) { + uncommitedBlockActors.put(loc, actorId); + } + + public Integer getUncommitedBlockActor(Location loc) { + return uncommitedBlockActors.get(loc); } public void processStatements(Connection conn) throws SQLException { @@ -966,6 +997,7 @@ public class Consumer extends Thread { } } } + uncommitedBlockActors.clear(); } public PreparedStatement getOrPrepareStatement(Connection conn, String sql, int autoGeneratedKeys) throws SQLException { diff --git a/src/main/java/de/diddiz/LogBlock/WorldEditor.java b/src/main/java/de/diddiz/LogBlock/WorldEditor.java index 9f0d347..f590d9a 100644 --- a/src/main/java/de/diddiz/LogBlock/WorldEditor.java +++ b/src/main/java/de/diddiz/LogBlock/WorldEditor.java @@ -194,7 +194,7 @@ public class WorldEditor implements Runnable { return PerformResult.NO_ACTION; } } - if (block.getType() != setBlock.getMaterial() && !replaceAnyway.contains(block.getType())) { + if (block.getType() != setBlock.getMaterial() && !block.isEmpty() && !replaceAnyway.contains(block.getType())) { return PerformResult.NO_ACTION; } if (state instanceof InventoryHolder && replacedBlock.getMaterial() != block.getType()) { diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 723d9be..0f520c2 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -34,6 +34,7 @@ public class Config { public static boolean dumpDeletedLog; public static boolean logBedExplosionsAsPlayerWhoTriggeredThese; public static boolean logCreeperExplosionsAsPlayerWhoTriggeredThese, logPlayerInfo; + public static boolean logFireSpreadAsPlayerWhoCreatedIt; public static LogKillsLevel logKillsLevel; public static Set dontRollback, replaceAnyway; public static int rollbackMaxTime, rollbackMaxArea; @@ -93,6 +94,7 @@ public class Config { def.put("clearlog.autoClearLogDelay", "6h"); def.put("logging.logBedExplosionsAsPlayerWhoTriggeredThese", true); def.put("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false); + def.put("logging.logFireSpreadAsPlayerWhoCreatedIt", true); def.put("logging.logKillsLevel", "PLAYERS"); def.put("logging.logEnvironmentalKills", false); def.put("logging.logPlayerInfo", false); @@ -100,7 +102,7 @@ public class Config { def.put("logging.hiddenBlocks", Arrays.asList(Material.AIR.name(), Material.CAVE_AIR.name(), Material.VOID_AIR.name())); def.put("logging.ignoredChat", Arrays.asList("/register", "/login")); def.put("rollback.dontRollback", Arrays.asList(Material.LAVA.name(), Material.TNT.name(), Material.FIRE.name())); - def.put("rollback.replaceAnyway", Arrays.asList(Material.LAVA.name(), Material.WATER.name(), Material.FIRE.name())); + def.put("rollback.replaceAnyway", Arrays.asList(Material.LAVA.name(), Material.WATER.name(), Material.FIRE.name(), Material.GRASS_BLOCK.name())); def.put("rollback.maxTime", "2 days"); def.put("rollback.maxArea", 50); def.put("lookup.defaultDist", 20); @@ -169,6 +171,7 @@ public class Config { autoClearLogDelay = parseTimeSpec(config.getString("clearlog.autoClearLogDelay").split(" ")); logBedExplosionsAsPlayerWhoTriggeredThese = config.getBoolean("logging.logBedExplosionsAsPlayerWhoTriggeredThese", true); logCreeperExplosionsAsPlayerWhoTriggeredThese = config.getBoolean("logging.logCreeperExplosionsAsPlayerWhoTriggeredThese", false); + logFireSpreadAsPlayerWhoCreatedIt = config.getBoolean("logging.logFireSpreadAsPlayerWhoCreatedIt", true); logPlayerInfo = config.getBoolean("logging.logPlayerInfo", true); try { logKillsLevel = LogKillsLevel.valueOf(config.getString("logging.logKillsLevel").toUpperCase()); diff --git a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java index 87ad67f..4d4ebc8 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/BlockBurnLogging.java @@ -3,6 +3,8 @@ 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; + import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.entity.Player; @@ -16,6 +18,7 @@ import org.bukkit.event.player.PlayerInteractEvent; import static de.diddiz.LogBlock.config.Config.isLogging; import static de.diddiz.util.LoggingUtil.smartLogBlockBreak; +import static de.diddiz.util.LoggingUtil.smartLogBlockReplace; import static de.diddiz.util.LoggingUtil.smartLogFallables; public class BlockBurnLogging extends LoggingListener { @@ -26,16 +29,16 @@ 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, new Actor("Fire"), event.getBlock()); - smartLogFallables(consumer, new Actor("Fire"), event.getBlock()); + smartLogBlockReplace(consumer, new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null), event.getBlock(), Material.FIRE.createBlockData()); + smartLogFallables(consumer, new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null), event.getBlock()); } } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onBlockIgnite(BlockIgniteEvent event) { - Actor actor = new Actor("Fire"); + Actor actor = new Actor("Fire", Config.logFireSpreadAsPlayerWhoCreatedIt ? event.getIgnitingBlock() : null); if (event.getCause() == IgniteCause.FLINT_AND_STEEL) { - if(event.getIgnitingEntity() != null) { + if (event.getIgnitingEntity() != null) { return; // handled in block place } else { actor = new Actor("Dispenser"); diff --git a/src/main/java/de/diddiz/util/LoggingUtil.java b/src/main/java/de/diddiz/util/LoggingUtil.java index c502622..73d2f97 100644 --- a/src/main/java/de/diddiz/util/LoggingUtil.java +++ b/src/main/java/de/diddiz/util/LoggingUtil.java @@ -101,6 +101,10 @@ public class LoggingUtil { } public static void smartLogBlockBreak(Consumer consumer, Actor actor, Block origin) { + smartLogBlockReplace(consumer, actor, origin, null); + } + + public static void smartLogBlockReplace(Consumer consumer, Actor actor, Block origin, BlockData replacedWith) { WorldConfig wcfg = getWorldConfig(origin.getWorld()); if (wcfg == null) { @@ -187,7 +191,11 @@ public class LoggingUtil { } // Do this down here so that the block is added after blocks sitting on it - consumer.queueBlockBreak(actor, origin.getState()); + if (replacedWith == null) { + consumer.queueBlockBreak(actor, origin.getState()); + } else { + consumer.queueBlockReplace(actor, origin.getState(), replacedWith); + } } public static String checkText(String text) {