Merge pull request #288 from slide23/kills

Add support for searching kill logs
This commit is contained in:
Ammar Askar
2012-12-10 21:37:06 -08:00
5 changed files with 262 additions and 6 deletions

11
src/main/java/de/diddiz/LogBlock/CommandsHandler.java Normal file → Executable file
View File

@@ -401,6 +401,12 @@ public class CommandsHandler implements CommandExecutor
params.needDate = true;
params.needPlayer = true;
params.needMessage = true;
} else if (params.bct == BlockChangeType.KILLS) {
params.needDate = true;
params.needPlayer = true;
params.needKiller = true;
params.needVictim = true;
params.needWeapon = true;
} else {
params.needDate = true;
params.needType = true;
@@ -429,7 +435,10 @@ public class CommandsHandler implements CommandExecutor
if (blockchanges.size() > linesPerPage)
sender.sendMessage(ChatColor.DARK_AQUA.toString() + blockchanges.size() + " changes found." + (blockchanges.size() == linesLimit ? " Use 'limit -1' to see all changes." : ""));
if (params.sum != SummarizationMode.NONE)
sender.sendMessage(ChatColor.GOLD + "Created - Destroyed - " + (params.sum == SummarizationMode.TYPES ? "Block" : "Player"));
if (params.bct == BlockChangeType.KILLS && params.sum == SummarizationMode.PLAYERS)
sender.sendMessage(ChatColor.GOLD + "Kills - Killed - Player");
else
sender.sendMessage(ChatColor.GOLD + "Created - Destroyed - " + (params.sum == SummarizationMode.TYPES ? "Block" : "Player"));
showPage(sender, 1);
} else {
sender.sendMessage(ChatColor.DARK_AQUA + "No results found.");

View File

@@ -0,0 +1,65 @@
package de.diddiz.LogBlock;
import java.sql.ResultSet;
import java.sql.SQLException;
import org.bukkit.Location;
import org.bukkit.inventory.ItemStack;
import de.diddiz.LogBlock.config.Config;
public class Kill implements LookupCacheElement
{
final long id, date;
public final Location loc;
final String killerName, victimName;
final int weapon;
public Kill(String killerName, String victimName, int weapon, Location loc) {
id = 0;
date = System.currentTimeMillis() / 1000;
this.loc = loc;
this.killerName = killerName;
this.victimName = victimName;
this.weapon = weapon;
}
public Kill(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;
killerName = p.needKiller ? rs.getString("killer") : null;
victimName = p.needVictim ? rs.getString("victim") : null;
weapon = p.needWeapon ? rs.getInt("weapon") : 0;
}
@Override
public String toString() {
final StringBuilder msg = new StringBuilder();
if (date > 0)
msg.append(Config.formatter.format(date)).append(" ");
msg.append(killerName).append(" killed ").append(victimName);
if (loc != null)
msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ());
String weaponName = prettyItemName(new ItemStack(weapon));
msg.append(" with " + weaponName); // + ("aeiou".contains(weaponName.substring(0, 1)) ? "an " : "a " )
return msg.toString();
}
@Override
public Location getLocation() {
return loc;
}
@Override
public String getMessage() {
return toString();
}
public String prettyItemName(ItemStack i) {
String item = i.getType().toString().replace('_', ' ' ).toLowerCase();
if(item.equals("air")) {
item = "fist";
}
return item;
}
}

View File

@@ -18,6 +18,11 @@ public class LookupCacheElementFactory
public LookupCacheElement getLookupCacheElement(ResultSet rs) throws SQLException {
if (params.bct == BlockChangeType.CHAT)
return new ChatMessage(rs, params);
if (params.bct == BlockChangeType.KILLS)
if (params.sum == SummarizationMode.NONE)
return new Kill(rs, params);
else if (params.sum == SummarizationMode.PLAYERS)
return new SummedKills(rs, params, spaceFactor);
if (params.sum == SummarizationMode.NONE)
return new BlockChange(rs, params);
return new SummedBlockChanges(rs, params, spaceFactor);

155
src/main/java/de/diddiz/LogBlock/QueryParams.java Normal file → Executable file
View File

@@ -5,6 +5,7 @@ import static de.diddiz.LogBlock.config.Config.defaultDist;
import static de.diddiz.LogBlock.config.Config.defaultTime;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
import static de.diddiz.LogBlock.config.Config.isLogged;
import static de.diddiz.LogBlock.config.Config.isLogging;
import static de.diddiz.util.BukkitUtils.friendlyWorldname;
import static de.diddiz.util.BukkitUtils.getBlockEquivalents;
import static de.diddiz.util.MaterialName.materialName;
@@ -26,23 +27,27 @@ import org.bukkit.World;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import de.diddiz.LogBlock.config.Config;
import de.diddiz.util.Block;
public final class QueryParams implements Cloneable
{
private static final Set<Integer> keywords = new HashSet<Integer>(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()));
private static final Set<Integer> keywords = new HashSet<Integer>(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()));
public BlockChangeType bct = BlockChangeType.BOTH;
public int limit = -1, before = 0, since = 0, radius = -1;
public Location loc = null;
public Order order = Order.DESC;
public List<String> players = new ArrayList<String>();
public boolean excludePlayersMode = false, prepareToolQuery = false, silent = false;
public List<String> killers = new ArrayList<String>();
public List<String> victims = new ArrayList<String>();
public boolean excludePlayersMode = false, excludeKillersMode = false, excludeVictimsMode = false, prepareToolQuery = false, silent = false;
public Selection sel = null;
public SummarizationMode sum = SummarizationMode.NONE;
public List<Block> types = new ArrayList<Block>();
public World world = null;
public String match = null;
public boolean needCount = false, needId = false, needDate = false, needType = false, needData = false, needPlayer = false, needCoords = false, needSignText = false, needChestAccess = false, needMessage = false;
public boolean needCount = false, needId = false, needDate = false, needType = false, needData = false, needPlayer = false, needCoords = false, needSignText = false, needChestAccess = false, needMessage = false, needKiller = false, needVictim = false, needWeapon = false;
private final LogBlock logblock;
public QueryParams(LogBlock logblock) {
@@ -84,6 +89,38 @@ public final class QueryParams implements Cloneable
from += "INNER JOIN `lb-players` USING (playerid) ";
return select + " " + from + getWhere() + "ORDER BY date " + order + ", id " + order + " " + getLimit();
}
if (bct == BlockChangeType.KILLS) {
if (sum == SummarizationMode.NONE) {
String select = "SELECT ";
if (needCount)
select += "COUNT(*) AS count";
else {
if (needId)
select += "id, ";
if (needDate)
select += "date, ";
if (needPlayer || needKiller)
select += "killers.playername as killer, ";
if (needPlayer || needVictim)
select += "victims.playername as victim, ";
if (needWeapon)
select += "weapon, ";
if (needCoords)
select += "x, y, z, ";
select = select.substring(0, select.length() - 2);
}
String from = "FROM `" + getTable() + "-kills` ";
if (needPlayer || needKiller || killers.size() > 0)
from += "INNER JOIN `lb-players` as killers ON (killer=killers.playerid) ";
if (needPlayer || needVictim || victims.size() > 0)
from += "INNER JOIN `lb-players` as victims ON (victim=victims.playerid) ";
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();
}
if (sum == SummarizationMode.NONE) {
String select = "SELECT ";
if (needCount)
@@ -131,6 +168,8 @@ public final class QueryParams implements Cloneable
title.append("chest accesses ");
else if (bct == BlockChangeType.CHAT)
title.append("chat messages ");
else if (bct == BlockChangeType.KILLS)
title.append("kills ");
else {
if (!types.isEmpty()) {
final String[] blocknames = new String[types.size()];
@@ -146,6 +185,14 @@ public final class QueryParams implements Cloneable
else
title.append("changes ");
}
if (killers.size() > 10)
title.append(excludeKillersMode ? "without" : "from").append(" many killers ");
else if (!killers.isEmpty())
title.append(excludeKillersMode ? "without" : "from").append(" ").append(listing(killers.toArray(new String[killers.size()]), ", ", " and ")).append(" ");
if (victims.size() > 10)
title.append(excludeVictimsMode ? "without" : "of").append(" many victims ");
else if (!victims.isEmpty())
title.append(excludeVictimsMode ? "without" : "of").append(" victim").append(victims.size() != 1 ? "s" : "").append(" ").append(listing(victims.toArray(new String[victims.size()]), ", ", " and ")).append(" ");
if (players.size() > 10)
title.append(excludePlayersMode ? "without" : "from").append(" many players ");
else if (!players.isEmpty())
@@ -193,6 +240,52 @@ public final class QueryParams implements Cloneable
else
where.append("message ").append(unlike ? "NOT " : "").append("LIKE '%").append(unlike ? match.substring(1) : match).append("%' AND ");
}
} else if (blockChangeType == BlockChangeType.KILLS) {
if (!players.isEmpty())
if (!excludePlayersMode) {
where.append('(');
for (final String killerName : players)
where.append("killers.playername = '").append(killerName).append("' OR ");
for (final String victimName : players)
where.append("victims.playername = '").append(victimName).append("' OR ");
where.delete(where.length() - 4, where.length());
where.append(") AND ");
} else {
for (final String killerName : players)
where.append("killers.playername != '").append(killerName).append("' AND ");
for (final String victimName : players)
where.append("victims.playername != '").append(victimName).append("' AND ");
}
if (!killers.isEmpty())
if (!excludeKillersMode) {
where.append('(');
for (final String killerName : killers)
where.append("killers.playername = '").append(killerName).append("' OR ");
where.delete(where.length() - 4, where.length());
where.append(") AND ");
} else
for (final String killerName : killers)
where.append("killers.playername != '").append(killerName).append("' AND ");
if (!victims.isEmpty())
if (!excludeVictimsMode) {
where.append('(');
for (final String victimName : victims)
where.append("victims.playername = '").append(victimName).append("' OR ");
where.delete(where.length() - 4, where.length());
where.append(") AND ");
} else
for (final String victimName : victims)
where.append("victims.playername != '").append(victimName).append("' AND ");
if (loc != null) {
if (radius == 0)
where.append("x = '").append(loc.getBlockX()).append("' AND y = '").append(loc.getBlockY()).append("' AND z = '").append(loc.getBlockZ()).append("' AND ");
else if (radius > 0)
where.append("x > '").append(loc.getBlockX() - radius).append("' AND x < '").append(loc.getBlockX() + radius).append("' AND y > '").append(loc.getBlockY() - radius).append("' AND y < '").append(loc.getBlockY() + radius).append("' AND z > '").append(loc.getBlockZ() - radius).append("' AND z < '").append(loc.getBlockZ() + radius).append("' AND ");
} else if (sel != null)
where.append("x >= '").append(sel.getMinimumPoint().getBlockX()).append("' AND x <= '").append(sel.getMaximumPoint().getBlockX()).append("' AND y >= '").append(sel.getMinimumPoint().getBlockY()).append("' AND y <= '").append(sel.getMaximumPoint().getBlockY()).append("' AND z >= '").append(sel.getMinimumPoint().getBlockZ()).append("' AND z <= '").append(sel.getMaximumPoint().getBlockZ()).append("' AND ");
} else {
switch (blockChangeType) {
case ALL:
@@ -290,7 +383,7 @@ public final class QueryParams implements Cloneable
} else if (sel != null)
where.append("x >= '").append(sel.getMinimumPoint().getBlockX()).append("' AND x <= '").append(sel.getMaximumPoint().getBlockX()).append("' AND y >= '").append(sel.getMinimumPoint().getBlockY()).append("' AND y <= '").append(sel.getMaximumPoint().getBlockY()).append("' AND z >= '").append(sel.getMinimumPoint().getBlockZ()).append("' AND z <= '").append(sel.getMaximumPoint().getBlockZ()).append("' AND ");
}
if (!players.isEmpty() && sum != SummarizationMode.PLAYERS)
if (!players.isEmpty() && sum != SummarizationMode.PLAYERS && blockChangeType != BlockChangeType.KILLS)
if (!excludePlayersMode) {
where.append('(');
for (final String playerName : players)
@@ -341,6 +434,53 @@ public final class QueryParams implements Cloneable
players.add(matches.size() == 1 ? matches.get(0).getName() : playerName.replaceAll("[^a-zA-Z0-9_]", ""));
}
}
} else if (param.equals("killer")) {
if (values.length < 1)
throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'");
for (final String killerName : values)
if (killerName.length() > 0) {
if (killerName.contains("!"))
excludeVictimsMode = true;
if (killerName.contains("\""))
killers.add(killerName.replaceAll("[^a-zA-Z0-9_]", ""));
else {
final List<Player> matches = logblock.getServer().matchPlayer(killerName);
if (matches.size() > 1)
throw new IllegalArgumentException("Ambiguous victimname '" + param + "'");
killers.add(matches.size() == 1 ? matches.get(0).getName() : killerName.replaceAll("[^a-zA-Z0-9_]", ""));
}
}
} else if (param.equals("victim")) {
if (values.length < 1)
throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'");
for (final String victimName : values)
if (victimName.length() > 0) {
if (victimName.contains("!"))
excludeVictimsMode = true;
if (victimName.contains("\""))
victims.add(victimName.replaceAll("[^a-zA-Z0-9_]", ""));
else {
final List<Player> matches = logblock.getServer().matchPlayer(victimName);
if (matches.size() > 1)
throw new IllegalArgumentException("Ambiguous victimname '" + param + "'");
victims.add(matches.size() == 1 ? matches.get(0).getName() : victimName.replaceAll("[^a-zA-Z0-9_]", ""));
}
}
} else if (param.equals("weapon")) {
if (values.length < 1)
throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'");
for (final String weaponName : values) {
Material mat = Material.matchMaterial(weaponName);
if (mat == null)
try {
mat = Material.getMaterial(Integer.parseInt(weaponName));
} catch (NumberFormatException e) {
throw new IllegalArgumentException("Data type not a valid number: '" + weaponName + "'");
}
if (mat == null)
throw new IllegalArgumentException("No material matching: '" + weaponName + "'");
types.add(new Block(mat.getId(), -1));
}
} else if (param.equals("block") || param.equals("type")) {
if (values.length < 1)
throw new IllegalArgumentException("No or wrong count of arguments for '" + param + "'");
@@ -421,6 +561,9 @@ public final class QueryParams implements Cloneable
bct = BlockChangeType.CHESTACCESS;
else if (param.equals("chat"))
bct = BlockChangeType.CHAT;
else if (param.equals("kills")) {
bct = BlockChangeType.KILLS;
}
else if (param.equals("all"))
bct = BlockChangeType.ALL;
else if (param.equals("limit")) {
@@ -461,6 +604,8 @@ 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 (types.size() > 0)
for (final Set<Integer> equivalent : getBlockEquivalents()) {
boolean found = false;
@@ -588,7 +733,7 @@ public final class QueryParams implements Cloneable
public static enum BlockChangeType
{
ALL, BOTH, CHESTACCESS, CREATED, DESTROYED, CHAT
ALL, BOTH, CHESTACCESS, CREATED, DESTROYED, CHAT, KILLS
}
public static enum Order

View File

@@ -0,0 +1,32 @@
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 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);
this.spaceFactor = spaceFactor;
}
@Override
public Location getLocation() {
return null;
}
@Override
public String getMessage() {
return kills + spaces((int)((6 - String.valueOf(kills).length()) / spaceFactor)) + killed + spaces((int)((7 - String.valueOf(killed).length()) / spaceFactor)) + playerName;
}
}