forked from LogBlock/LogBlock
Incomplete entity logging
This commit is contained in:
@ -3,6 +3,7 @@ package de.diddiz.LogBlock;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.projectiles.BlockProjectileSource;
|
||||
import org.bukkit.projectiles.ProjectileSource;
|
||||
|
||||
@ -86,9 +87,14 @@ public class Actor {
|
||||
public static Actor actorFromEntity(Entity entity) {
|
||||
if (entity instanceof Player) {
|
||||
return new Actor(entityName(entity), entity.getUniqueId());
|
||||
} else {
|
||||
return new Actor(entityName(entity));
|
||||
}
|
||||
if (entity instanceof Projectile) {
|
||||
ProjectileSource shooter = ((Projectile) entity).getShooter();
|
||||
if (shooter != null) {
|
||||
return actorFromProjectileSource(shooter);
|
||||
}
|
||||
}
|
||||
return new Actor(entityName(entity));
|
||||
}
|
||||
|
||||
public static Actor actorFromEntity(EntityType entity) {
|
||||
@ -109,17 +115,19 @@ public class Actor {
|
||||
|
||||
/**
|
||||
* Generate an Actor object from a String name, trying to guess if it's an online player
|
||||
* and if so, setting the UUID accordingly. This only checks against currently online
|
||||
* and if so, setting the UUID accordingly. This only checks against currently online
|
||||
* players and is a "best effort" attempt for use with the pre-UUID API
|
||||
* <p>
|
||||
* If you know something is an entity (player or otherwise) use the {@link #actorFromEntity(org.bukkit.entity.Entity) }
|
||||
* or {@link #actorFromEntity(org.bukkit.entity.EntityType) } methods
|
||||
* <p>
|
||||
* If you know something is a server effect (like gravity) use {@link #Actor(java.lang.String)}
|
||||
*
|
||||
* @deprecated Only use this if you have a String of unknown origin
|
||||
*
|
||||
* @param actorName String of unknown origin
|
||||
* @return
|
||||
* @param actorName
|
||||
* String of unknown origin
|
||||
* @return
|
||||
*/
|
||||
public static Actor actorFromString(String actorName) {
|
||||
Collection<? extends Player> players = Bukkit.getServer().getOnlinePlayers();
|
||||
|
@ -26,16 +26,19 @@ import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
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.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.entity.Projectile;
|
||||
import org.bukkit.inventory.Inventory;
|
||||
@ -43,6 +46,7 @@ import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
import org.bukkit.projectiles.ProjectileSource;
|
||||
|
||||
import de.diddiz.LogBlock.EntityChange.EntityChangeType;
|
||||
import de.diddiz.LogBlock.blockstate.BlockStateCodecSign;
|
||||
import de.diddiz.LogBlock.blockstate.BlockStateCodecs;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
@ -52,8 +56,10 @@ import de.diddiz.util.Utils;
|
||||
public class Consumer extends Thread {
|
||||
private final Deque<Row> queue = new ArrayDeque<Row>();
|
||||
private final LogBlock logblock;
|
||||
private final Map<Actor, Integer> playerIds = new HashMap<Actor, Integer>();
|
||||
private final Map<Actor, Integer> uncommitedPlayerIds = new HashMap<Actor, Integer>();
|
||||
private final Map<Actor, Integer> playerIds = new HashMap<>();
|
||||
private final Map<Actor, Integer> uncommitedPlayerIds = new HashMap<>();
|
||||
private final Map<World, Map<UUID, Integer>> uncommitedEntityIds = new HashMap<>();
|
||||
|
||||
private long addEntryCounter;
|
||||
private long nextWarnCounter;
|
||||
|
||||
@ -495,6 +501,7 @@ public class Consumer extends Thread {
|
||||
currentRows.clear();
|
||||
playerIds.putAll(uncommitedPlayerIds);
|
||||
uncommitedPlayerIds.clear();
|
||||
uncommitedEntityIds.clear();
|
||||
lastCommitsFailed = 0;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
@ -520,6 +527,7 @@ public class Consumer extends Thread {
|
||||
currentRows.clear();
|
||||
batchHelper.reset();
|
||||
uncommitedPlayerIds.clear();
|
||||
uncommitedEntityIds.clear();
|
||||
if (conn != null) {
|
||||
try {
|
||||
conn.close();
|
||||
@ -657,6 +665,48 @@ public class Consumer extends Thread {
|
||||
return uncommitedPlayerIds.containsKey(actor);
|
||||
}
|
||||
|
||||
private int getEntityUUID(Connection conn, World world, UUID uuid) throws SQLException {
|
||||
Map<UUID, Integer> uncommitedEntityIdsHere = uncommitedEntityIds.get(world);
|
||||
if (uncommitedEntityIdsHere == null) {
|
||||
uncommitedEntityIdsHere = new HashMap<>();
|
||||
uncommitedEntityIds.put(world, uncommitedEntityIdsHere);
|
||||
}
|
||||
Integer existing = uncommitedEntityIdsHere.get(uuid);
|
||||
if (existing != null) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
// Odd query contruction is to work around innodb auto increment behaviour - bug #492
|
||||
final String table = getWorldConfig(world).table;
|
||||
String uuidString = uuid.toString();
|
||||
Statement state = conn.createStatement();
|
||||
String q1 = "INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) SELECT '" + mysqlTextEscape(uuidString) + "' FROM `" + table + "-entityids` WHERE NOT EXISTS (SELECT NULL FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(uuidString) + "') LIMIT 1";
|
||||
String q2 = "SELECT entityid FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(uuidString) + "'";
|
||||
int q1Result = state.executeUpdate(q1);
|
||||
ResultSet rs = state.executeQuery(q2);
|
||||
if (rs.next()) {
|
||||
uncommitedEntityIdsHere.put(uuid, rs.getInt(1));
|
||||
}
|
||||
rs.close();
|
||||
// if there was not any row in the table the query above does not work, so we need to try this one
|
||||
if (!uncommitedEntityIdsHere.containsKey(uuid)) {
|
||||
state.executeUpdate("INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) VALUES ('" + mysqlTextEscape(uuidString) + "')");
|
||||
rs = state.executeQuery(q2);
|
||||
if (rs.next()) {
|
||||
uncommitedEntityIdsHere.put(uuid, rs.getInt(1));
|
||||
} else {
|
||||
logblock.getLogger().warning("[Consumer] Failed to add entity uuid " + uuidString.toString());
|
||||
logblock.getLogger().warning("[Consumer-Debug] World: " + world.getName());
|
||||
logblock.getLogger().warning("[Consumer-Debug] Query 1: " + q1);
|
||||
logblock.getLogger().warning("[Consumer-Debug] Query 1 - Result: " + q1Result);
|
||||
logblock.getLogger().warning("[Consumer-Debug] Query 2: " + q2);
|
||||
}
|
||||
rs.close();
|
||||
}
|
||||
state.close();
|
||||
return uncommitedEntityIdsHere.get(uuid);
|
||||
}
|
||||
|
||||
private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter, YamlConfiguration stateBefore, YamlConfiguration stateAfter, ChestAccess ca) {
|
||||
if (typeBefore == null || typeBefore.getMaterial() == Material.CAVE_AIR || typeBefore.getMaterial() == Material.VOID_AIR) {
|
||||
typeBefore = Bukkit.createBlockData(Material.AIR);
|
||||
@ -696,6 +746,13 @@ public class Consumer extends Thread {
|
||||
addQueueLast(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, Utils.serializeYamlConfiguration(stateBefore), typeMaterialId, typeStateId, Utils.serializeYamlConfiguration(stateAfter), ca));
|
||||
}
|
||||
|
||||
public void queueEntityModification(Actor actor, UUID entityId, EntityType entityType, Location loc, EntityChangeType changeType, YamlConfiguration data) {
|
||||
if (actor == null || loc == null || changeType == null || entityId == null || entityType == null || hiddenPlayers.contains(actor.getName().toLowerCase()) || !isLogged(loc.getWorld())) {
|
||||
return;
|
||||
}
|
||||
addQueueLast(new EntityRow(loc, actor, entityType, entityId, changeType, Utils.serializeYamlConfiguration(data)));
|
||||
}
|
||||
|
||||
private String playerID(Actor actor) {
|
||||
if (actor == null) {
|
||||
return "NULL";
|
||||
@ -965,6 +1022,67 @@ public class Consumer extends Thread {
|
||||
}
|
||||
}
|
||||
|
||||
private class EntityRow extends EntityChange implements Row {
|
||||
final String statementString;
|
||||
final String selectActorIdStatementString;
|
||||
|
||||
public EntityRow(Location loc, Actor actor, EntityType type, UUID entityid, EntityChangeType changeType, byte[] data) {
|
||||
super(System.currentTimeMillis() / 1000, loc, actor, type, entityid, changeType, data);
|
||||
statementString = getWorldConfig(loc.getWorld()).insertEntityStatementString;
|
||||
selectActorIdStatementString = getWorldConfig(loc.getWorld()).selectBlockActorIdStatementString;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getInserts() {
|
||||
final String table = getWorldConfig(loc.getWorld()).table;
|
||||
final String[] inserts = new String[2];
|
||||
|
||||
inserts[0] = "INSERT IGNORE INTO `" + table + "-entityids` (entityuuid) SELECT '" + mysqlTextEscape(entityid.toString()) + "' FROM `" + table + "-entityids` WHERE NOT EXISTS (SELECT NULL FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(entityid.toString()) + "') LIMIT 1";
|
||||
int entityTypeId = EntityTypeConverter.getOrAddEntityTypeId(type);
|
||||
inserts[1] = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(actor) + ", " + "(SELECT entityid FROM `" + table + "-entityids` WHERE entityuuid = '" + mysqlTextEscape(entityid.toString()) + "')"
|
||||
+ ", " + entityTypeId + ", '" + loc.getBlockX() + "', " + safeY(loc) + ", '" + loc.getBlockZ() + "', " + changeType.ordinal() + ", " + Utils.mysqlPrepareBytesForInsertAllowNull(data) + ");";
|
||||
return inserts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Actor[] getActors() {
|
||||
return new Actor[] { actor };
|
||||
}
|
||||
|
||||
@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, sourceActor);
|
||||
smt.setInt(3, getEntityUUID(conn, loc.getWorld(), entityid));
|
||||
smt.setInt(4, EntityTypeConverter.getOrAddEntityTypeId(type));
|
||||
smt.setInt(5, loc.getBlockX());
|
||||
smt.setInt(6, safeY(loc));
|
||||
smt.setInt(7, loc.getBlockZ());
|
||||
smt.setInt(8, changeType.ordinal());
|
||||
smt.setBytes(9, data);
|
||||
batchHelper.addBatch(smt, null);
|
||||
}
|
||||
}
|
||||
|
||||
private int safeY(Location loc) {
|
||||
int safeY = loc.getBlockY();
|
||||
if (safeY < 0)
|
||||
|
98
src/main/java/de/diddiz/LogBlock/EntityChange.java
Normal file
98
src/main/java/de/diddiz/LogBlock/EntityChange.java
Normal file
@ -0,0 +1,98 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.entity.ArmorStand;
|
||||
import org.bukkit.entity.EntityType;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
|
||||
public class EntityChange implements LookupCacheElement {
|
||||
public static enum EntityChangeType {
|
||||
CREATE,
|
||||
KILL,
|
||||
MODIFY,
|
||||
ADDEQUIP,
|
||||
REMOVEEQUIP;
|
||||
|
||||
private static EntityChangeType[] values = values();
|
||||
|
||||
public static EntityChangeType valueOf(int ordinal) {
|
||||
return values[ordinal];
|
||||
}
|
||||
}
|
||||
|
||||
public final long id, date;
|
||||
public final Location loc;
|
||||
public final Actor actor;
|
||||
public final EntityType type;
|
||||
public final UUID entityid;
|
||||
public final EntityChangeType changeType;
|
||||
public final byte[] data;
|
||||
|
||||
public EntityChange(long date, Location loc, Actor actor, EntityType type, UUID entityid, EntityChangeType changeType, byte[] data) {
|
||||
id = 0;
|
||||
this.date = date;
|
||||
this.loc = loc;
|
||||
this.actor = actor;
|
||||
this.type = type;
|
||||
this.entityid = entityid;
|
||||
this.changeType = changeType;
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
public EntityChange(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;
|
||||
type = p.needType ? EntityTypeConverter.getEntityType(rs.getInt("entitytypeid")) : null;
|
||||
entityid = p.needType ? UUID.fromString(rs.getString("entityuuid")) : null;
|
||||
changeType = p.needType ? EntityChangeType.valueOf(rs.getInt("action")) : null;
|
||||
data = p.needType ? rs.getBytes("data") : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
final StringBuilder msg = new StringBuilder();
|
||||
if (date > 0) {
|
||||
msg.append(Config.formatter.format(date)).append(" ");
|
||||
}
|
||||
if (actor != null) {
|
||||
msg.append(actor.getName()).append(" ");
|
||||
}
|
||||
if (type != null) {
|
||||
boolean living = LivingEntity.class.isAssignableFrom(type.getEntityClass()) && !ArmorStand.class.isAssignableFrom(type.getDeclaringClass());
|
||||
if (changeType == EntityChangeType.CREATE) {
|
||||
msg.append("created ");
|
||||
} else if (changeType == EntityChangeType.KILL) {
|
||||
msg.append(living ? "killed " : "destroyed ");
|
||||
} else if (changeType == EntityChangeType.ADDEQUIP) {
|
||||
msg.append("added an item to ");
|
||||
} else if (changeType == EntityChangeType.REMOVEEQUIP) {
|
||||
msg.append("removed an item from ");
|
||||
} else if (changeType == EntityChangeType.MODIFY) {
|
||||
msg.append("modified ");
|
||||
}
|
||||
msg.append(type.name());
|
||||
}
|
||||
if (loc != null) {
|
||||
msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ());
|
||||
}
|
||||
return msg.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Location getLocation() {
|
||||
return loc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMessage() {
|
||||
return toString();
|
||||
}
|
||||
}
|
82
src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java
Normal file
82
src/main/java/de/diddiz/LogBlock/EntityTypeConverter.java
Normal file
@ -0,0 +1,82 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
public class EntityTypeConverter {
|
||||
private static EntityType[] idToEntityType = new EntityType[10];
|
||||
private static HashMap<EntityType, Integer> entityTypeToId = new HashMap<>();
|
||||
private static int nextEntityTypeId;
|
||||
|
||||
public static int getOrAddEntityTypeId(EntityType entityType) {
|
||||
Integer key = entityTypeToId.get(entityType);
|
||||
while (key == null) {
|
||||
key = nextEntityTypeId;
|
||||
Connection conn = LogBlock.getInstance().getConnection();
|
||||
try {
|
||||
conn.setAutoCommit(false);
|
||||
PreparedStatement smt = conn.prepareStatement("INSERT IGNORE INTO `lb-entitytypes` (id, name) VALUES (?, ?)");
|
||||
smt.setInt(1, key);
|
||||
smt.setString(2, entityType.name());
|
||||
boolean couldAdd = smt.executeUpdate() > 0;
|
||||
conn.commit();
|
||||
smt.close();
|
||||
if (couldAdd) {
|
||||
internalAddEntityType(key, entityType);
|
||||
} else {
|
||||
initializeEntityTypes(conn);
|
||||
}
|
||||
} catch (SQLException e) {
|
||||
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not update lb-entitytypes", e);
|
||||
} finally {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
key = entityTypeToId.get(entityType);
|
||||
}
|
||||
return key.intValue();
|
||||
}
|
||||
|
||||
public static EntityType getEntityType(int entityTypeId) {
|
||||
return idToEntityType[entityTypeId];
|
||||
}
|
||||
|
||||
public static void initializeEntityTypes(Connection connection) throws SQLException {
|
||||
Statement smt = connection.createStatement();
|
||||
ResultSet rs = smt.executeQuery("SELECT id, name FROM `lb-entitytypes`");
|
||||
while (rs.next()) {
|
||||
int key = rs.getInt(1);
|
||||
EntityType entityType = EntityType.valueOf(rs.getString(2));
|
||||
internalAddEntityType(key, entityType);
|
||||
}
|
||||
rs.close();
|
||||
smt.close();
|
||||
connection.close();
|
||||
}
|
||||
|
||||
private synchronized static void internalAddEntityType(int key, EntityType entityType) {
|
||||
entityTypeToId.put(entityType, key);
|
||||
int length = idToEntityType.length;
|
||||
while (length <= key) {
|
||||
length = (length * 3 / 2) + 5;
|
||||
}
|
||||
if (length > idToEntityType.length) {
|
||||
idToEntityType = Arrays.copyOf(idToEntityType, length);
|
||||
}
|
||||
idToEntityType[key] = entityType;
|
||||
if (nextEntityTypeId <= key) {
|
||||
nextEntityTypeId = key + 1;
|
||||
}
|
||||
}
|
||||
}
|
@ -5,6 +5,8 @@ import de.diddiz.LogBlock.listeners.*;
|
||||
import de.diddiz.LogBlock.questioner.Questioner;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
import de.diddiz.util.MySQLConnectionPool;
|
||||
import de.diddiz.worldedit.AdvancedKillLogging;
|
||||
import de.diddiz.worldedit.WorldEditHelper;
|
||||
import de.diddiz.worldedit.WorldEditLoggingHook;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Material;
|
||||
@ -89,6 +91,7 @@ public class LogBlock extends JavaPlugin {
|
||||
updater.checkTables();
|
||||
MaterialConverter.initializeMaterials(getConnection());
|
||||
MaterialConverter.getOrAddMaterialId(Material.AIR.getKey()); // AIR must be the first entry
|
||||
EntityTypeConverter.initializeEntityTypes(getConnection());
|
||||
if (updater.update()) {
|
||||
load(this);
|
||||
}
|
||||
@ -100,7 +103,7 @@ public class LogBlock extends JavaPlugin {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pm.getPlugin("WorldEdit") != null) {
|
||||
if (WorldEditHelper.hasWorldEdit()) {
|
||||
new WorldEditLoggingHook(this).hook();
|
||||
}
|
||||
commandsHandler = new CommandsHandler(this);
|
||||
@ -186,6 +189,7 @@ public class LogBlock extends JavaPlugin {
|
||||
if (isLogging(Logging.DRAGONEGGTELEPORT)) {
|
||||
pm.registerEvents(new DragonEggLogging(this), this);
|
||||
}
|
||||
pm.registerEvents(new AdvancedKillLogging(this), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3,12 +3,13 @@ package de.diddiz.LogBlock;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import de.diddiz.util.Utils;
|
||||
import de.diddiz.worldedit.CuboidRegion;
|
||||
import de.diddiz.worldedit.WorldEditHelper;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@ -120,6 +121,17 @@ public final class QueryParams implements Cloneable {
|
||||
}
|
||||
return from;
|
||||
}
|
||||
if (bct == BlockChangeType.ENTITIES) {
|
||||
String from = "FROM `" + getTable() + "-entities` ";
|
||||
|
||||
if (needPlayer || players.size() > 0) {
|
||||
from += "INNER JOIN `lb-players` USING (playerid) ";
|
||||
}
|
||||
if (!needCount && needType) {
|
||||
from += "LEFT JOIN `" + getTable() + "-entityids` USING (entityid) ";
|
||||
}
|
||||
return from;
|
||||
}
|
||||
|
||||
String from = "FROM `" + getTable() + "-blocks` ";
|
||||
|
||||
@ -262,6 +274,9 @@ public final class QueryParams implements Cloneable {
|
||||
}
|
||||
throw new IllegalStateException("Invalid summarization for kills");
|
||||
}
|
||||
if (bct == BlockChangeType.ENTITIES) {
|
||||
throw new IllegalStateException("Not implemented yet");
|
||||
}
|
||||
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() + "-blocks` 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() + "-blocks` 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 {
|
||||
@ -281,6 +296,8 @@ public final class QueryParams implements Cloneable {
|
||||
title.append("chat messages ");
|
||||
} else if (bct == BlockChangeType.KILLS) {
|
||||
title.append("kills ");
|
||||
} else if (bct == BlockChangeType.ENTITIES) {
|
||||
title.append("entity changes ");
|
||||
} else {
|
||||
if (!types.isEmpty()) {
|
||||
if (excludeBlocksMode) {
|
||||
@ -745,9 +762,8 @@ public final class QueryParams implements Cloneable {
|
||||
if (player == null) {
|
||||
throw new IllegalArgumentException("You have to be a player to use selection");
|
||||
}
|
||||
final Plugin we = player.getServer().getPluginManager().getPlugin("WorldEdit");
|
||||
if (we != null) {
|
||||
setSelection(CuboidRegion.fromPlayerSelection(player, we));
|
||||
if (WorldEditHelper.hasWorldEdit()) {
|
||||
setSelection(CuboidRegion.fromPlayerSelection(player));
|
||||
} else {
|
||||
throw new IllegalArgumentException("WorldEdit not found!");
|
||||
}
|
||||
@ -786,6 +802,8 @@ public final class QueryParams implements Cloneable {
|
||||
bct = BlockChangeType.CHAT;
|
||||
} else if (param.equals("kills")) {
|
||||
bct = BlockChangeType.KILLS;
|
||||
} else if (param.equals("entities")) {
|
||||
bct = BlockChangeType.ENTITIES;
|
||||
} else if (param.equals("all")) {
|
||||
bct = BlockChangeType.ALL;
|
||||
} else if (param.equals("limit")) {
|
||||
@ -963,7 +981,7 @@ public final class QueryParams implements Cloneable {
|
||||
}
|
||||
|
||||
public static enum BlockChangeType {
|
||||
ALL, BOTH, CHESTACCESS, CREATED, DESTROYED, CHAT, KILLS
|
||||
ALL, BOTH, CHESTACCESS, CREATED, DESTROYED, CHAT, KILLS, ENTITIES
|
||||
}
|
||||
|
||||
public static enum Order {
|
||||
|
@ -779,15 +779,17 @@ class Updater {
|
||||
}
|
||||
createTable(dbm, state, "lb-materials", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset);
|
||||
createTable(dbm, state, "lb-blockstates", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset);
|
||||
createTable(dbm, state, "lb-entitytypes", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset);
|
||||
|
||||
for (final WorldConfig wcfg : getLoggedWorlds()) {
|
||||
createTable(dbm, state, wcfg.table + "-blocks", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced SMALLINT UNSIGNED NOT NULL, replacedData SMALLINT NOT NULL, type SMALLINT UNSIGNED NOT NULL, typeData SMALLINT 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 " + charset);
|
||||
createTable(dbm, state, wcfg.table + "-chestdata", "(id INT UNSIGNED NOT NULL, item MEDIUMBLOB, itemremove TINYINT, itemtype SMALLINT NOT NULL DEFAULT '0', PRIMARY KEY (id))");
|
||||
createTable(dbm, state, wcfg.table + "-state", "(id INT UNSIGNED NOT NULL, replacedState MEDIUMBLOB NULL, typeState MEDIUMBLOB 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))");
|
||||
}
|
||||
createTable(dbm, state, wcfg.table + "-entityids", "(entityid INT UNSIGNED NOT NULL AUTO_INCREMENT, entityuuid VARCHAR(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, PRIMARY KEY (entityid), UNIQUE KEY (entityuuid))");
|
||||
createTable(dbm, state, wcfg.table + "-entities", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, entityid INT UNSIGNED NOT NULL, entitytypeid INT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, action TINYINT UNSIGNED NOT NULL, data MEDIUMBLOB NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))");
|
||||
}
|
||||
state.close();
|
||||
conn.close();
|
||||
|
@ -16,6 +16,7 @@ public class WorldConfig extends LoggingEnabledMapping {
|
||||
public final String selectBlockActorIdStatementString;
|
||||
public final String insertBlockStateStatementString;
|
||||
public final String insertBlockChestDataStatementString;
|
||||
public final String insertEntityStatementString;
|
||||
|
||||
public WorldConfig(String world, File file) throws IOException {
|
||||
this.world = world;
|
||||
@ -42,5 +43,6 @@ public class WorldConfig extends LoggingEnabledMapping {
|
||||
selectBlockActorIdStatementString = "SELECT playerid FROM `" + table + "-blocks` WHERE x = ? AND y = ? AND z = ? ORDER BY date DESC LIMIT 1";
|
||||
insertBlockStateStatementString = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(?, ?, ?)";
|
||||
insertBlockChestDataStatementString = "INSERT INTO `" + table + "-chestdata` (item, itemremove, id, itemtype) values (?, ?, ?, ?)";
|
||||
insertEntityStatementString = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
}
|
||||
}
|
||||
|
50
src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java
Normal file
50
src/main/java/de/diddiz/worldedit/AdvancedKillLogging.java
Normal file
@ -0,0 +1,50 @@
|
||||
package de.diddiz.worldedit;
|
||||
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Animals;
|
||||
import org.bukkit.entity.LivingEntity;
|
||||
import org.bukkit.entity.Villager;
|
||||
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.Actor;
|
||||
import de.diddiz.LogBlock.EntityChange;
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.listeners.LoggingListener;
|
||||
|
||||
public class AdvancedKillLogging extends LoggingListener {
|
||||
|
||||
public AdvancedKillLogging(LogBlock lb) {
|
||||
super(lb);
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
|
||||
public void onEntityDeath(EntityDeathEvent event) {
|
||||
LivingEntity entity = event.getEntity();
|
||||
if (!(entity instanceof Animals) && !(entity instanceof Villager)) {
|
||||
return;
|
||||
}
|
||||
Actor killer;
|
||||
EntityDamageEvent lastDamage = entity.getLastDamageCause();
|
||||
if (lastDamage instanceof EntityDamageByEntityEvent) {
|
||||
killer = Actor.actorFromEntity(((EntityDamageByEntityEvent) lastDamage).getDamager());
|
||||
} else {
|
||||
killer = new Actor(lastDamage.getCause().toString());
|
||||
}
|
||||
Location location = entity.getLocation();
|
||||
YamlConfiguration data = new YamlConfiguration();
|
||||
data.set("x", location.getX());
|
||||
data.set("y", location.getX());
|
||||
data.set("z", location.getX());
|
||||
data.set("yaw", location.getYaw());
|
||||
data.set("pitch", location.getPitch());
|
||||
|
||||
data.set("worldedit", WorldEditHelper.serializeEntity(entity));
|
||||
|
||||
consumer.queueEntityModification(killer, entity.getUniqueId(), entity.getType(), location, EntityChange.EntityChangeType.KILL, data);
|
||||
}
|
||||
}
|
@ -29,7 +29,8 @@ public class CuboidRegion implements Cloneable {
|
||||
this.max.setZ(Math.max(first.getBlockZ(),second.getBlockZ()));
|
||||
}
|
||||
|
||||
public static CuboidRegion fromPlayerSelection(Player player, Plugin worldEditPlugin) {
|
||||
public static CuboidRegion fromPlayerSelection(Player player) {
|
||||
Plugin worldEditPlugin = player.getServer().getPluginManager().getPlugin("WorldEdit");
|
||||
LocalSession session = ((WorldEditPlugin) worldEditPlugin).getSession(player);
|
||||
World world = player.getWorld();
|
||||
com.sk89q.worldedit.world.World weWorld = BukkitAdapter.adapt(world);
|
||||
|
60
src/main/java/de/diddiz/worldedit/WorldEditHelper.java
Normal file
60
src/main/java/de/diddiz/worldedit/WorldEditHelper.java
Normal file
@ -0,0 +1,60 @@
|
||||
package de.diddiz.worldedit;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Entity;
|
||||
import org.bukkit.plugin.Plugin;
|
||||
|
||||
import com.sk89q.jnbt.NBTOutputStream;
|
||||
import com.sk89q.worldedit.bukkit.BukkitAdapter;
|
||||
import com.sk89q.worldedit.entity.BaseEntity;
|
||||
|
||||
public class WorldEditHelper {
|
||||
private static boolean checkedForWorldEdit;
|
||||
private static boolean hasWorldEdit;
|
||||
|
||||
public static boolean hasWorldEdit() {
|
||||
if (!checkedForWorldEdit) {
|
||||
checkedForWorldEdit = true;
|
||||
Plugin worldEdit = Bukkit.getPluginManager().getPlugin("WorldEdit");
|
||||
hasWorldEdit = worldEdit != null;
|
||||
Internal.setWorldEdit(worldEdit);
|
||||
}
|
||||
return hasWorldEdit;
|
||||
}
|
||||
|
||||
public static byte[] serializeEntity(Entity entity) {
|
||||
if (!hasWorldEdit()) {
|
||||
return null;
|
||||
}
|
||||
return Internal.serializeEntity(entity);
|
||||
}
|
||||
|
||||
private static class Internal {
|
||||
// private static WorldEditPlugin worldEdit;
|
||||
|
||||
public static void setWorldEdit(Plugin worldEdit) {
|
||||
// Internal.worldEdit = (WorldEditPlugin) worldEdit;
|
||||
}
|
||||
|
||||
public static byte[] serializeEntity(Entity entity) {
|
||||
com.sk89q.worldedit.entity.Entity weEntity = BukkitAdapter.adapt(entity);
|
||||
BaseEntity state = weEntity.getState();
|
||||
if (state != null) {
|
||||
try {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
NBTOutputStream nbtos = new NBTOutputStream(baos);
|
||||
nbtos.writeNamedTag("entity", state.getNbtData());
|
||||
nbtos.close();
|
||||
return baos.toByteArray();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("This IOException should be impossible", e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user