From 92e9564fa78c4ef4708a82e2eafd1a440a1f25ae Mon Sep 17 00:00:00 2001 From: Robin Kupper Date: Thu, 14 Apr 2011 22:27:31 +0200 Subject: [PATCH] Fixed double kill issue. --- src/de/diddiz/LogBlock/Config.java | 4 + src/de/diddiz/LogBlock/Consumer.java | 105 ++++++++++++++++++++++++++- src/de/diddiz/LogBlock/LogBlock.java | 28 ++++++- 3 files changed, 132 insertions(+), 5 deletions(-) diff --git a/src/de/diddiz/LogBlock/Config.java b/src/de/diddiz/LogBlock/Config.java index 7374a77..d6f50c8 100644 --- a/src/de/diddiz/LogBlock/Config.java +++ b/src/de/diddiz/LogBlock/Config.java @@ -24,6 +24,7 @@ public class Config { final boolean logFire; final boolean logLeavesDecay; final boolean logChestAccess; + final boolean logKills; final List dontRollback; final List replaceAnyway; final int defaultDist; @@ -86,6 +87,8 @@ public class Config { config.setProperty("logging.logChestAccess", false); if (!subkeys.contains("logLeavesDecay")) config.setProperty("logging.logLeavesDecay", false); + if (!subkeys.contains("logKills")) + config.setProperty("logging.logKills", false); subkeys = config.getKeys("rollback"); if (subkeys == null) subkeys = new ArrayList(); @@ -120,6 +123,7 @@ public class Config { logFire = config.getBoolean("logging.logFire", false); logChestAccess = config.getBoolean("logging.logChestAccess", false); logLeavesDecay = config.getBoolean("logging.logLeavesDecay", false); + logKills = config.getBoolean("logging.logKills", false); dontRollback = config.getIntList("rollback.dontRollback", null); replaceAnyway = config.getIntList("rollback.replaceAnyway", null); defaultDist = config.getInt("lookup.defaultDist", 20); diff --git a/src/de/diddiz/LogBlock/Consumer.java b/src/de/diddiz/LogBlock/Consumer.java index 1706ca3..625bd28 100644 --- a/src/de/diddiz/LogBlock/Consumer.java +++ b/src/de/diddiz/LogBlock/Consumer.java @@ -4,19 +4,33 @@ import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.HashMap; import java.util.HashSet; import java.util.TimerTask; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; import org.bukkit.block.Block; +import org.bukkit.entity.Creeper; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Ghast; +import org.bukkit.entity.Giant; +import org.bukkit.entity.PigZombie; import org.bukkit.entity.Player; +import org.bukkit.entity.Skeleton; +import org.bukkit.entity.Slime; +import org.bukkit.entity.Spider; +import org.bukkit.entity.Wolf; +import org.bukkit.entity.Zombie; public class Consumer extends TimerTask implements Runnable { private LinkedBlockingQueue bqueue = new LinkedBlockingQueue(); + private LinkedBlockingQueue kqueue = new LinkedBlockingQueue(); private HashSet hiddenplayers = new HashSet(); - private LogBlock logblock; + private HashMap lastAttackedEntity = new HashMap(); + private HashMap lastAttackTime = new HashMap(); + private LogBlock logblock; Consumer (LogBlock logblock) { this.logblock = logblock; @@ -53,8 +67,26 @@ public class Consumer extends TimerTask implements Runnable LogBlock.log.info("[LogBlock] Failed to queue block for " + playerName); } + public void queueKill(Entity attacker, Entity defender) { + if (lastAttackedEntity.containsKey(attacker.getEntityId()) && lastAttackedEntity.get(attacker.getEntityId()) == defender.getEntityId() && System.currentTimeMillis() - lastAttackTime.get(attacker.getEntityId()) < 3000) + return; + String table = LogBlock.config.tables.get(defender.getWorld().getName().hashCode()); + if (table == null) + return; + int weapon = 0; + if (attacker instanceof Player && ((Player)attacker).getItemInHand() != null) + weapon = ((Player)attacker).getItemInHand().getTypeId(); + String attackerName = getEntityName(attacker); + String defenderName = getEntityName(defender); + if (attackerName == null || defenderName == null) + return; + lastAttackedEntity.put(attacker.getEntityId(), defender.getEntityId()); + lastAttackTime.put(attacker.getEntityId(), System.currentTimeMillis()); + kqueue.add(new KillRow(table, getEntityName(attacker), getEntityName(defender), weapon)); + } + public int getQueueSize() { - return bqueue.size(); + return bqueue.size() + kqueue.size(); } public boolean hide(Player player) { @@ -67,13 +99,13 @@ public class Consumer extends TimerTask implements Runnable return true; } } - + public synchronized void run() { Connection conn = logblock.pool.getConnection(); if (conn == null) return; Statement state = null; - BlockRow b; + BlockRow b; KillRow k; int count = 0; if (bqueue.size() > 100) LogBlock.log.info("[LogBlock Consumer] Queue overloaded. Size: " + bqueue.size()); @@ -102,6 +134,13 @@ public class Consumer extends TimerTask implements Runnable count++; } conn.commit(); + while (!kqueue.isEmpty() && count < 1000 && (System.currentTimeMillis() - start < 100 || count < 100)) { + k = kqueue.poll(); + if (k == null) + continue; + state.execute("INSERT INTO `" + k.table + "-kills` (date, killer, victim, weapon) SELECT now(), playerid, (SELECT playerid FROM `lb-players` WHERE playername = '" + k.victim + "'), " + k.weapon + " FROM `lb-players` WHERE playername = '" + k.killer + "'"); + } + conn.commit(); } catch (SQLException ex) { LogBlock.log.log(Level.SEVERE, "[LogBlock Consumer] SQL exception", ex); } finally { @@ -116,6 +155,30 @@ public class Consumer extends TimerTask implements Runnable } } + private String getEntityName(Entity entity) { + if (entity instanceof Player) + return ((Player)entity).getName(); + if (entity instanceof Creeper) + return "Creeper"; + if (entity instanceof Ghast) + return "Ghast"; + if (entity instanceof Giant) + return "Giant"; + if (entity instanceof PigZombie) + return "PigZombie"; + if (entity instanceof Skeleton) + return "Skeleton"; + if (entity instanceof Slime) + return "Slime"; + if (entity instanceof Spider) + return "Spider"; + if (entity instanceof Wolf) + return "Wolf"; + if (entity instanceof Zombie) + return "Zombie"; + return null; + } + private class ChestAccess { public short inType, outType; @@ -152,4 +215,38 @@ public class Consumer extends TimerTask implements Runnable this.ca = null; } } + + private class KillRow + { + public String table; + public String killer; + public String victim; + public int weapon; + + KillRow(String table, String attacker, String defender, int weapon) { + this.table = table; + this.killer = attacker; + this.victim = defender; + this.weapon = weapon; + } + + @Override + public int hashCode() { + return killer.hashCode() * 31 + victim.hashCode(); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + KillRow k = (KillRow)obj; + if (!killer.equals(k.killer)) + return false; + if (!victim.equals(k.victim)) + return false; + return true; + } + } } diff --git a/src/de/diddiz/LogBlock/LogBlock.java b/src/de/diddiz/LogBlock/LogBlock.java index 2e90591..ca85aa6 100644 --- a/src/de/diddiz/LogBlock/LogBlock.java +++ b/src/de/diddiz/LogBlock/LogBlock.java @@ -17,7 +17,9 @@ import org.bukkit.block.Block; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.entity.Creeper; +import org.bukkit.entity.Entity; import org.bukkit.entity.Fireball; +import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; import org.bukkit.entity.TNTPrimed; import org.bukkit.event.Event; @@ -29,6 +31,8 @@ import org.bukkit.event.block.BlockListener; import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.block.LeavesDecayEvent; import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.EntityDamageEvent; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.EntityListener; import org.bukkit.event.player.PlayerBucketEmptyEvent; @@ -105,6 +109,7 @@ public class LogBlock extends JavaPlugin new Thread(new ClearLog(this)).start(); LBBlockListener lbBlockListener = new LBBlockListener(); LBPlayerListener lbPlayerListener = new LBPlayerListener(); + LBEntityListener lbEntityListener = new LBEntityListener(); PluginManager pm = getServer().getPluginManager(); pm.registerEvent(Type.PLAYER_INTERACT, new LBToolPlayerListener(), Event.Priority.Normal, this); pm.registerEvent(Type.PLAYER_JOIN, lbPlayerListener, Event.Priority.Normal, this); @@ -121,11 +126,13 @@ public class LogBlock extends JavaPlugin if (config.logFire) pm.registerEvent(Type.BLOCK_BURN, lbBlockListener, Event.Priority.Monitor, this); if (config.logExplosions) - pm.registerEvent(Type.ENTITY_EXPLODE, new LBEntityListener(), Event.Priority.Monitor, this); + pm.registerEvent(Type.ENTITY_EXPLODE, lbEntityListener, Event.Priority.Monitor, this); if (config.logLeavesDecay) pm.registerEvent(Type.LEAVES_DECAY, lbBlockListener, Event.Priority.Monitor, this); if (config.logChestAccess) pm.registerEvent(Type.PLAYER_INTERACT, lbPlayerListener, Event.Priority.Monitor, this); + if (config.logKills) + pm.registerEvent(Type.ENTITY_DAMAGE, lbEntityListener, Event.Priority.Monitor, this); consumer = new Consumer(this); if (config.useBukkitScheduler) { if (getServer().getScheduler().scheduleAsyncRepeatingTask(this, consumer, config.delay * 20, config.delay * 20) > 0) @@ -552,6 +559,25 @@ public class LogBlock extends JavaPlugin consumer.queueBlock(name, block, block.getTypeId(), 0, block.getData()); } } + + @Override + public void onEntityDamage(EntityDamageEvent event) { + if (event.isCancelled()) + return; + if (!(event instanceof EntityDamageByEntityEvent)) + return; + if (!(event.getEntity() instanceof LivingEntity)) + return; + LivingEntity victim = (LivingEntity)event.getEntity(); + Entity killer = ((EntityDamageByEntityEvent)event).getDamager(); + if (!(victim instanceof Player) && !(killer instanceof Player)) + return; + if (victim.getHealth() - event.getDamage() > 0) + return; + if (victim.getHealth() <= 0 ) + return; + consumer.queueKill(killer, victim); + } } public class LBPlayerListener extends PlayerListener