diff --git a/src/main/java/de/diddiz/LogBlock/EntityLogging.java b/src/main/java/de/diddiz/LogBlock/EntityLogging.java new file mode 100644 index 0000000..80c3878 --- /dev/null +++ b/src/main/java/de/diddiz/LogBlock/EntityLogging.java @@ -0,0 +1,28 @@ +package de.diddiz.LogBlock; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.bukkit.entity.EntityType; + +public enum EntityLogging { + SPAWN(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.IRON_GOLEM.name(), EntityType.SNOWMAN.name() }), + DESTROY(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.VILLAGER.name(), EntityType.IRON_GOLEM.name(), EntityType.SNOWMAN.name(), "ANIMAL" }), + MODIFY(new String[] { "ALL" }); + + public static final int length = EntityLogging.values().length; + private final List defaultEnabled; + + private EntityLogging() { + this(null); + } + + private EntityLogging(String[] defaultEnabled) { + this.defaultEnabled = defaultEnabled == null ? Collections.emptyList() : Collections.unmodifiableList(Arrays.asList(defaultEnabled)); + } + + public List getDefaultEnabled() { + return defaultEnabled; + } +} diff --git a/src/main/java/de/diddiz/LogBlock/config/Config.java b/src/main/java/de/diddiz/LogBlock/config/Config.java index 708f2e2..0aecb97 100644 --- a/src/main/java/de/diddiz/LogBlock/config/Config.java +++ b/src/main/java/de/diddiz/LogBlock/config/Config.java @@ -6,6 +6,7 @@ import de.diddiz.util.ComparableVersion; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.configuration.ConfigurationSection; +import org.bukkit.entity.Entity; import org.bukkit.permissions.PermissionDefault; import java.io.File; @@ -322,6 +323,11 @@ public class Config { public static Collection getLoggedWorlds() { return worldConfigs.values(); } + + public static boolean isLogging(World world, EntityLogging logging, Entity entity) { + final WorldConfig wcfg = worldConfigs.get(world.getName()); + return wcfg != null && wcfg.isLogging(logging, entity); + } } class LoggingEnabledMapping { diff --git a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java index b8542b9..50ba6aa 100644 --- a/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java +++ b/src/main/java/de/diddiz/LogBlock/config/WorldConfig.java @@ -1,13 +1,30 @@ package de.diddiz.LogBlock.config; +import de.diddiz.LogBlock.EntityLogging; +import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.Logging; +import de.diddiz.util.Utils; + import org.bukkit.configuration.file.YamlConfiguration; +import org.bukkit.entity.Ambient; +import org.bukkit.entity.Animals; +import org.bukkit.entity.ArmorStand; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.LivingEntity; +import org.bukkit.entity.Monster; +import org.bukkit.entity.Player; +import org.bukkit.entity.WaterMob; import java.io.File; import java.io.IOException; +import java.util.EnumMap; +import java.util.EnumSet; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.logging.Level; public class WorldConfig extends LoggingEnabledMapping { public final String world; @@ -19,6 +36,8 @@ public class WorldConfig extends LoggingEnabledMapping { public final String insertEntityStatementString; public final String updateEntityUUIDString; + private final EnumMap entityLogging = new EnumMap<>(EntityLogging.class); + public WorldConfig(String world, File file) throws IOException { this.world = world; final Map def = new HashMap(); @@ -34,6 +53,12 @@ public class WorldConfig extends LoggingEnabledMapping { config.set(e.getKey(), e.getValue()); } } + for (EntityLogging el : EntityLogging.values()) { + if (!(config.get("entity." + el.name().toLowerCase()) instanceof List)) { + config.set("entity." + el.name().toLowerCase(), el.getDefaultEnabled()); + } + entityLogging.put(el, new EntitiyLoggingList(config.getStringList("entity." + el.name().toLowerCase()))); + } config.save(file); table = config.getString("table"); for (final Logging l : Logging.values()) { @@ -47,4 +72,65 @@ public class WorldConfig extends LoggingEnabledMapping { insertEntityStatementString = "INSERT INTO `" + table + "-entities` (date, playerid, entityid, entitytypeid, x, y, z, action, data) VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?)"; updateEntityUUIDString = "UPDATE `" + table + "-entityids` SET entityuuid = ? WHERE entityid = ?"; } + + public boolean isLogging(EntityLogging logging, Entity entity) { + return entityLogging.get(logging).isLogging(entity); + } + + private class EntitiyLoggingList { + private final EnumSet logged = EnumSet.noneOf(EntityType.class); + private final boolean logAll; + private final boolean logAnimals; + private final boolean logMonsters; + private final boolean logLiving; + + public EntitiyLoggingList(List types) { + boolean all = false; + boolean animals = false; + boolean monsters = false; + boolean living = false; + for (String type : types) { + EntityType et = Utils.matchEntityType(type); + if (et != null) { + logged.add(et); + } else { + if (type.equalsIgnoreCase("all")) { + all = true; + } else if (type.equalsIgnoreCase("animal") || type.equalsIgnoreCase("animals")) { + animals = true; + } else if (type.equalsIgnoreCase("monster") || type.equalsIgnoreCase("monsters")) { + monsters = true; + } else if (type.equalsIgnoreCase("living")) { + living = true; + } else { + LogBlock.getInstance().getLogger().log(Level.WARNING, "Unkown entity type in config for " + world + ": " + type); + } + } + } + logAll = all; + logAnimals = animals; + logMonsters = monsters; + logLiving = living; + } + + public boolean isLogging(Entity entity) { + if (entity == null || (entity instanceof Player)) { + return false; + } + EntityType type = entity.getType(); + if (logAll || logged.contains(type)) { + return true; + } + if (logLiving && LivingEntity.class.isAssignableFrom(entity.getClass()) && !(entity instanceof ArmorStand)) { + return true; + } + if (logAnimals && (Animals.class.isAssignableFrom(entity.getClass()) || WaterMob.class.isAssignableFrom(entity.getClass()) || Ambient.class.isAssignableFrom(entity.getClass()))) { + return true; + } + if (logMonsters && (Monster.class.isAssignableFrom(entity.getClass()) || entity.getType() == EntityType.SLIME || entity.getType() == EntityType.WITHER || entity.getType() == EntityType.ENDER_DRAGON || entity.getType() == EntityType.SHULKER || entity.getType() == EntityType.GHAST)) { + return true; + } + return false; + } + } } diff --git a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java index 1517320..35e575a 100644 --- a/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java +++ b/src/main/java/de/diddiz/LogBlock/listeners/AdvancedEntityLogging.java @@ -2,18 +2,20 @@ package de.diddiz.LogBlock.listeners; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.BlockFace; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.entity.Animals; import org.bukkit.entity.ArmorStand; import org.bukkit.entity.Entity; -import org.bukkit.entity.Golem; import org.bukkit.entity.Hanging; +import org.bukkit.entity.IronGolem; import org.bukkit.entity.LivingEntity; import org.bukkit.entity.Player; -import org.bukkit.entity.Villager; +import org.bukkit.entity.Snowman; +import org.bukkit.entity.Wither; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.block.Action; +import org.bukkit.event.block.BlockPlaceEvent; import org.bukkit.event.entity.CreatureSpawnEvent; import org.bukkit.event.entity.CreatureSpawnEvent.SpawnReason; import org.bukkit.event.entity.EntityDamageByEntityEvent; @@ -30,7 +32,9 @@ import org.bukkit.scheduler.BukkitRunnable; import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.EntityChange; +import de.diddiz.LogBlock.EntityLogging; import de.diddiz.LogBlock.LogBlock; +import de.diddiz.LogBlock.config.Config; import de.diddiz.worldedit.WorldEditHelper; public class AdvancedEntityLogging extends LoggingListener { @@ -55,20 +59,25 @@ public class AdvancedEntityLogging extends LoggingListener { lastSpawnerEgg = false; } + private void setLastSpawner(Player player, Class spawning, boolean spawnEgg) { + lastSpawner = player; + lastSpawning = spawning; + lastSpawnerEgg = spawnEgg; + } + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onEntityDeath(EntityDeathEvent event) { - LivingEntity entity = event.getEntity(); - if (!(entity instanceof Animals) && !(entity instanceof Villager) && !(entity instanceof Golem) && !(entity instanceof ArmorStand)) { - return; + public void onPlayerBlockPlace(BlockPlaceEvent event) { + Material placed = event.getBlock().getType(); + if (placed == Material.WITHER_SKELETON_SKULL) { + setLastSpawner(event.getPlayer(), Wither.class, false); + } else if (placed == Material.CARVED_PUMPKIN) { + Material below = event.getBlock().getRelative(BlockFace.DOWN).getType(); + if (below == Material.SNOW_BLOCK) { + setLastSpawner(event.getPlayer(), Snowman.class, false); + } else if (below == Material.IRON_BLOCK) { + setLastSpawner(event.getPlayer(), IronGolem.class, false); + } } - Actor actor; - EntityDamageEvent lastDamage = entity.getLastDamageCause(); - if (lastDamage instanceof EntityDamageByEntityEvent) { - actor = Actor.actorFromEntity(((EntityDamageByEntityEvent) lastDamage).getDamager()); - } else { - actor = new Actor(lastDamage.getCause().toString()); - } - queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @@ -78,13 +87,9 @@ public class AdvancedEntityLogging extends LoggingListener { if (inHand != null) { Material mat = inHand.getType(); if (mat == Material.ARMOR_STAND) { - lastSpawner = event.getPlayer(); - lastSpawning = ArmorStand.class; - lastSpawnerEgg = false; + setLastSpawner(event.getPlayer(), ArmorStand.class, false); } else if (mat.name().endsWith("_SPAWN_EGG")) { - lastSpawner = event.getPlayer(); - lastSpawning = null; - lastSpawnerEgg = true; + setLastSpawner(event.getPlayer(), null, true); } } } @@ -96,9 +101,7 @@ public class AdvancedEntityLogging extends LoggingListener { if (inHand != null) { Material mat = inHand.getType(); if (mat.name().endsWith("_SPAWN_EGG")) { - lastSpawner = event.getPlayer(); - lastSpawning = null; - lastSpawnerEgg = true; + setLastSpawner(event.getPlayer(), null, true); } } } @@ -110,42 +113,60 @@ public class AdvancedEntityLogging extends LoggingListener { return; } LivingEntity entity = event.getEntity(); - if (!(entity instanceof Animals) && !(entity instanceof Villager) && !(entity instanceof Golem) && !(entity instanceof ArmorStand)) { - return; - } - Actor actor = null; - if (lastSpawner != null) { - if (lastSpawnerEgg && event.getSpawnReason() == SpawnReason.SPAWNER_EGG) { - actor = Actor.actorFromEntity(lastSpawner); - } else if (lastSpawning != null && lastSpawning.isAssignableFrom(entity.getClass())) { - actor = Actor.actorFromEntity(lastSpawner); + if (Config.isLogging(entity.getWorld(), EntityLogging.SPAWN, entity)) { + Actor actor = null; + if (lastSpawner != null && lastSpawner.getWorld() == entity.getWorld() && lastSpawner.getLocation().distance(entity.getLocation()) < 10) { + if (lastSpawnerEgg && event.getSpawnReason() == SpawnReason.SPAWNER_EGG) { + actor = Actor.actorFromEntity(lastSpawner); + } else if (lastSpawning != null && lastSpawning.isAssignableFrom(entity.getClass())) { + actor = Actor.actorFromEntity(lastSpawner); + } } + if (actor == null) { + actor = new Actor(event.getSpawnReason().toString()); + } + queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE); } - if (actor == null) { - actor = new Actor(event.getSpawnReason().toString()); - } - queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE); } resetLastSpawner(); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) - public void onHangingBreak(HangingBreakEvent event) { - Entity entity = event.getEntity(); - Actor actor; - if (event instanceof HangingBreakByEntityEvent) { - actor = Actor.actorFromEntity(((HangingBreakByEntityEvent) event).getRemover()); - } else { - actor = new Actor(event.getCause().toString()); + public void onEntityDeath(EntityDeathEvent event) { + LivingEntity entity = event.getEntity(); + if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) { + Actor actor; + EntityDamageEvent lastDamage = entity.getLastDamageCause(); + if (lastDamage instanceof EntityDamageByEntityEvent) { + actor = Actor.actorFromEntity(((EntityDamageByEntityEvent) lastDamage).getDamager()); + } else { + actor = new Actor(lastDamage.getCause().toString()); + } + queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); } - queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); } @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) public void onHangingPlace(HangingPlaceEvent event) { Hanging entity = event.getEntity(); - Actor actor = Actor.actorFromEntity(event.getPlayer()); - queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE); + if (Config.isLogging(entity.getWorld(), EntityLogging.SPAWN, entity)) { + Actor actor = Actor.actorFromEntity(event.getPlayer()); + queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.CREATE); + } + } + + @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) + public void onHangingBreak(HangingBreakEvent event) { + Entity entity = event.getEntity(); + if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) { + Actor actor; + if (event instanceof HangingBreakByEntityEvent) { + actor = Actor.actorFromEntity(((HangingBreakByEntityEvent) event).getRemover()); + } else { + actor = new Actor(event.getCause().toString()); + } + queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); + } } protected void queueEntitySpawnOrKill(Entity entity, Actor actor, EntityChange.EntityChangeType changeType) { diff --git a/src/main/java/de/diddiz/util/Utils.java b/src/main/java/de/diddiz/util/Utils.java index baf0379..60306ff 100644 --- a/src/main/java/de/diddiz/util/Utils.java +++ b/src/main/java/de/diddiz/util/Utils.java @@ -10,6 +10,7 @@ import java.io.OutputStreamWriter; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.UUID; import java.util.regex.Matcher; @@ -23,6 +24,7 @@ import org.bukkit.Chunk; import org.bukkit.configuration.InvalidConfigurationException; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.inventory.ItemStack; import de.diddiz.LogBlock.LogBlock; @@ -316,4 +318,24 @@ public class Utils { } return null; } + + private static final HashMap types = new HashMap<>(); + static { + for (EntityType t : EntityType.values()) { + types.put(t.name().toLowerCase(), t); + @SuppressWarnings("deprecation") + String typeName = t.getName(); + if (typeName != null) { + types.put(typeName.toLowerCase(), t); + } + Class ec = t.getEntityClass(); + if (ec != null) { + types.put(ec.getSimpleName().toLowerCase(), t); + } + } + } + + public static EntityType matchEntityType(String typeName) { + return types.get(typeName.toLowerCase()); + } }