forked from LogBlock/LogBlock
Add support for searching kill logs
Add Commands 'kills' - Searches kill logs Add Params 'killer' - Limits logs to the player that did the killing 'victim' - Limits logs to the player that got killed
This commit is contained in:
11
src/main/java/de/diddiz/LogBlock/CommandsHandler.java
Normal file → Executable file
11
src/main/java/de/diddiz/LogBlock/CommandsHandler.java
Normal file → Executable 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.");
|
||||
|
65
src/main/java/de/diddiz/LogBlock/Kill.java
Executable file
65
src/main/java/de/diddiz/LogBlock/Kill.java
Executable 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;
|
||||
}
|
||||
}
|
5
src/main/java/de/diddiz/LogBlock/LookupCacheElementFactory.java
Normal file → Executable file
5
src/main/java/de/diddiz/LogBlock/LookupCacheElementFactory.java
Normal file → Executable 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
155
src/main/java/de/diddiz/LogBlock/QueryParams.java
Normal file → Executable 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
|
||||
|
32
src/main/java/de/diddiz/LogBlock/SummedKills.java
Executable file
32
src/main/java/de/diddiz/LogBlock/SummedKills.java
Executable 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;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user