Merge branch 'master' of github.com:LogBlock/LogBlock

This commit is contained in:
Ammar Askar
2013-08-08 18:47:28 +05:00
19 changed files with 340 additions and 65 deletions

View File

@@ -1,3 +1,7 @@
This plugin logs block changes such as breaking, placing, modifying, or burning to a MySQL Database. It can be used as an anti-griefing tool to find out who made a particular edit, or even roll back changes by certain players.
LogBlock
==========
Originally written by bootswithdefer, for hMod, ported to Bukkit by me, because of the inability to identfy griefers. BigBrother also did't work, so I was forced to do it myself. The honor belongs to bootswithdefer for the sourcecode, I only spent about 8 hours to transcribe. All functions except sign text logging shold work as in hMod. The use of permissions plugin is possible, but not necessary.
This plugin logs block changes such as breaking, placing, modifying, or burning to a MySQL Database. It can be used as an anti-griefing tool to find out who made a particular edit, or even roll back changes by certain players.
Originally written by bootswithdefer, for hMod, ported to Bukkit by me, because of the inability to identfy griefers. BigBrother also did't work, so I was forced to do it myself. The honor belongs to bootswithdefer for the sourcecode, I only spent about 8 hours to transcribe. All functions except sign text logging shold work as in hMod. The use of permissions plugin is possible, but not necessary.
Questioner: http://git.io/u2MxKQ

View File

@@ -45,7 +45,7 @@
<dependency>
<groupId>org.bukkit</groupId>
<artifactId>bukkit</artifactId>
<version>1.4.6-R0.3</version>
<version>1.6.1-R0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>

View File

@@ -3,9 +3,12 @@ package de.diddiz.LogBlock;
import static de.diddiz.util.MaterialName.materialName;
import java.sql.ResultSet;
import java.sql.SQLException;
import de.diddiz.util.BukkitUtils;
import org.bukkit.Location;
import de.diddiz.LogBlock.config.Config;
import org.bukkit.Material;
public class BlockChange implements LookupCacheElement
{
@@ -64,18 +67,31 @@ public class BlockChange implements LookupCacheElement
msg.append("took ").append(-ca.itemAmount).append("x ").append(materialName(ca.itemType, ca.itemData));
else
msg.append("put in ").append(ca.itemAmount).append("x ").append(materialName(ca.itemType, ca.itemData));
} else if (type == 23 || type == 54 || type == 61 || type == 62)
} else if (BukkitUtils.getContainerBlocks().contains(Material.getMaterial(type)))
msg.append("opened ").append(materialName(type));
else if (type == 64 || type == 71 || type == 96 || type == 107)
msg.append(data == 0 ? "opened" : "closed").append(" ").append(materialName(type));
else if (type == 64 || type == 71)
// This is a problem that will have to be addressed in LB 2,
// there is no way to tell from the top half of the block if
// the door is opened or closed.
msg.append("moved ").append(materialName(type));
// Trapdoor
else if (type == 96)
msg.append((data < 8 || data > 11) ? "opened" : "closed").append(" ").append(materialName(type));
// Fence gate
else if (type == 107)
msg.append(data > 3 ? "opened" : "closed").append(" ").append(materialName(type));
else if (type == 69)
msg.append("switched ").append(materialName(type));
else if (type == 77 || type == 143)
msg.append("pressed ").append(materialName(type));
else if (type == 92)
msg.append("ate a piece of ").append(materialName(type));
else if (type == 25 || type == 93 || type == 94)
else if (type == 25 || type == 93 || type == 94 || type == 149 || type == 150)
msg.append("changed ").append(materialName(type));
else if (type == 70 || type == 72 || type == 147 || type == 148)
msg.append("stepped on ").append(materialName(type));
else if (type == 132)
msg.append("ran into ").append(materialName(type));
} else if (type == 0)
msg.append("destroyed ").append(materialName(replaced, data));
else if (replaced == 0)

View File

@@ -464,8 +464,8 @@ public class Consumer extends TimerTask
PreparedStatement ps1 = null;
PreparedStatement ps = null;
try {
ps1 = connection.prepareStatement("INSERT INTO `" + table + "` (date, playerid, replaced, type, data, x, y, z) VALUES(?, " + playerID(playerName) + ", ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
ps1.setTimestamp(1, new Timestamp(date * 1000));
ps1 = connection.prepareStatement("INSERT INTO `" + table + "` (date, playerid, replaced, type, data, x, y, z) VALUES(FROM_UNIXTIME(?), " + playerID(playerName) + ", ?, ?, ?, ?, ?, ?)", Statement.RETURN_GENERATED_KEYS);
ps1.setLong(1, date );
ps1.setInt(2, replaced);
ps1.setInt(3, type);
ps1.setInt(4, data);
@@ -574,7 +574,7 @@ public class Consumer extends TimerTask
boolean noID = false;
Integer id;
String sql = "INSERT INTO `lb-chat` (date, playerid, message) VALUES (?, ";
String sql = "INSERT INTO `lb-chat` (date, playerid, message) VALUES (FROM_UNIXTIME(?), ";
if ((id = playerIDAsInt(playerName)) == null) {
noID = true;
sql += playerID(playerName) + ", ";
@@ -586,7 +586,7 @@ public class Consumer extends TimerTask
PreparedStatement ps = null;
try {
ps = connection.prepareStatement(sql);
ps.setTimestamp(1, new Timestamp(date * 1000));
ps.setLong(1, date);
if (!noID) {
ps.setInt(2, id);
ps.setString(3, message);

View File

@@ -149,8 +149,11 @@ public class LogBlock extends JavaPlugin
if (isLogging(Logging.CHESTACCESS)) {
pm.registerEvents(new ChestAccessLogging(this), this);
}
if (isLogging(Logging.SWITCHINTERACT) || isLogging(Logging.DOORINTERACT) || isLogging(Logging.CAKEEAT) || isLogging(Logging.DIODEINTERACT) || isLogging(Logging.NOTEBLOCKINTERACT))
if (isLogging(Logging.SWITCHINTERACT) || isLogging(Logging.DOORINTERACT) || isLogging(Logging.CAKEEAT) || isLogging(Logging.DIODEINTERACT) || isLogging(Logging.COMPARATORINTERACT) || isLogging(Logging.NOTEBLOCKINTERACT) || isLogging(Logging.PRESUREPLATEINTERACT) || isLogging(Logging.TRIPWIREINTERACT) || isLogging(Logging.CROPTRAMPLE))
pm.registerEvents(new InteractLogging(this), this);
if (isLogging(Logging.CREATURECROPTRAMPLE)) {
pm.registerEvents(new CreatureInteractLogging(this), this);
}
if (isLogging(Logging.KILL))
pm.registerEvents(new KillLogging(this), this);
if (isLogging(Logging.CHAT))
@@ -161,6 +164,8 @@ public class LogBlock extends JavaPlugin
pm.registerEvents(new WitherLogging(this), this);
if (isLogging(Logging.NATURALSTRUCTUREGROW) || isLogging(Logging.BONEMEALSTRUCTUREGROW))
pm.registerEvents(new StructureGrowLogging(this), this);
if (isLogging(Logging.GRASSGROWTH) || isLogging(Logging.MYCELIUMSPREAD) || isLogging(Logging.VINEGROWTH) || isLogging(Logging.MUSHROOMSPREAD))
pm.registerEvents(new BlockSpreadLogging(this), this);
if (logPlayerInfo)
pm.registerEvents(new PlayerInfoLogging(this), this);
}

View File

@@ -5,9 +5,12 @@ public enum Logging
BLOCKPLACE(true), BLOCKBREAK(true), SIGNTEXT, TNTEXPLOSION(true), CREEPEREXPLOSION(true),
GHASTFIREBALLEXPLOSION(true), ENDERDRAGON(true), MISCEXPLOSION, FIRE(true), LEAVESDECAY,
LAVAFLOW, WATERFLOW, CHESTACCESS, KILL, CHAT, SNOWFORM, SNOWFADE, DOORINTERACT,
SWITCHINTERACT, CAKEEAT, ENDERMEN, NOTEBLOCKINTERACT, DIODEINTERACT, NATURALSTRUCTUREGROW,
WITHER(true), WITHER_SKULL(true),
BONEMEALSTRUCTUREGROW, WORLDEDIT;
SWITCHINTERACT, CAKEEAT, ENDERMEN, NOTEBLOCKINTERACT, DIODEINTERACT, COMPARATORINTERACT,
PRESUREPLATEINTERACT, TRIPWIREINTERACT, CREATURECROPTRAMPLE, CROPTRAMPLE,
NATURALSTRUCTUREGROW, GRASSGROWTH, MYCELIUMSPREAD, VINEGROWTH, MUSHROOMSPREAD,
WITHER(true), WITHER_SKULL(true), BONEMEALSTRUCTUREGROW,
WORLDEDIT, TNTMINECARTEXPLOSION(true);
public static final int length = Logging.values().length;
private final boolean defaultEnabled;

View File

@@ -197,6 +197,26 @@ class Updater
}
config.set("version", "1.52");
}
this.logblock.getServer().getScheduler().runTaskAsynchronously(this.logblock, new Thread() {
@Override
public void run() {
final Connection conn = logblock.getConnection();
try {
conn.setAutoCommit(true);
final Statement st = conn.createStatement();
ResultSet rs = st.executeQuery("SELECT auto_increment FROM information_schema.columns AS col join information_schema.tables AS tab ON (col.table_schema=tab.table_schema AND col.table_name=tab.table_name) WHERE col.table_name = 'lb-players' AND col.column_name = 'playerid' AND col.data_type = 'smallint' AND col.table_schema = DATABASE() AND auto_increment > 65000;");
if (rs.next()) {
logblock.getLogger().warning("Your server reached 65000 players. You should soon update your database table schema - see FAQ: https://github.com/LogBlock/LogBlock/wiki/FAQ#logblock-your-server-reached-65000-players-");
}
st.close();
conn.close();
} catch (final SQLException ex) {
logblock.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
}
}
});
logblock.saveConfig();
return true;
}
@@ -208,15 +228,15 @@ class Updater
final Statement state = conn.createStatement();
final DatabaseMetaData dbm = conn.getMetaData();
conn.setAutoCommit(true);
createTable(dbm, state, "lb-players", "(playerid SMALLINT UNSIGNED NOT NULL AUTO_INCREMENT, playername varchar(32) NOT NULL, firstlogin DATETIME NOT NULL, lastlogin DATETIME NOT NULL, onlinetime INT UNSIGNED NOT NULL, ip varchar(255) NOT NULL, PRIMARY KEY (playerid), UNIQUE (playername))");
createTable(dbm, state, "lb-players", "(playerid INT UNSIGNED NOT NULL AUTO_INCREMENT, playername varchar(32) NOT NULL, firstlogin DATETIME NOT NULL, lastlogin DATETIME NOT NULL, onlinetime INT UNSIGNED NOT NULL, ip varchar(255) NOT NULL, PRIMARY KEY (playerid), UNIQUE (playername))");
if (isLogging(Logging.CHAT))
createTable(dbm, state, "lb-chat", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid SMALLINT UNSIGNED NOT NULL, message VARCHAR(255) NOT NULL, PRIMARY KEY (id), KEY playerid (playerid), FULLTEXT message (message)) ENGINE=MyISAM");
createTable(dbm, state, "lb-chat", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, message VARCHAR(255) NOT NULL, PRIMARY KEY (id), KEY playerid (playerid), FULLTEXT message (message)) ENGINE=MyISAM");
for (final WorldConfig wcfg : getLoggedWorlds()) {
createTable(dbm, state, wcfg.table, "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid SMALLINT UNSIGNED NOT NULL, replaced TINYINT UNSIGNED NOT NULL, type TINYINT UNSIGNED NOT NULL, data TINYINT UNSIGNED 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, "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, replaced TINYINT UNSIGNED NOT NULL, type TINYINT UNSIGNED NOT NULL, data TINYINT UNSIGNED 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))");
createTable(dbm, state, wcfg.table + "-chest", "(id INT UNSIGNED NOT NULL, itemtype SMALLINT UNSIGNED NOT NULL, itemamount SMALLINT NOT NULL, itemdata TINYINT UNSIGNED NOT 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 SMALLINT UNSIGNED, victim SMALLINT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x SMALLINT NOT NULL, y TINYINT UNSIGNED NOT NULL, z SMALLINT NOT NULL, PRIMARY KEY (id))");
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 SMALLINT NOT NULL, y TINYINT UNSIGNED NOT NULL, z SMALLINT NOT NULL, PRIMARY KEY (id))");
}
state.close();
conn.close();

View File

@@ -209,11 +209,6 @@ public class WorldEditor implements Runnable
final Block secBlock = bed.isHeadOfBed() ? block.getRelative(bed.getFacing().getOppositeFace()) : block.getRelative(bed.getFacing());
if (secBlock.getTypeId() == 0 && !secBlock.setTypeIdAndData(26, (byte)(bed.getData() | 8), true))
throw new WorldEditorException(secBlock.getTypeId(), 26, secBlock.getLocation());
} else if (curtype == 64 || curtype == 71) {
final byte blockData = block.getData();
final Block secBlock = (blockData & 8) == 8 ? block.getRelative(BlockFace.DOWN) : block.getRelative(BlockFace.UP);
if (secBlock.getTypeId() == 0 && !secBlock.setTypeIdAndData(curtype, (byte)(blockData | 8), true))
throw new WorldEditorException(secBlock.getTypeId(), curtype, secBlock.getLocation());
} else if ((curtype == 29 || curtype == 33) && (block.getData() & 8) > 0) {
final PistonBaseMaterial piston = (PistonBaseMaterial)block.getState().getData();
final Block secBlock = block.getRelative(piston.getFacing());

View File

@@ -129,7 +129,7 @@ public class Config
if (!config.contains(e.getKey()))
config.set(e.getKey(), e.getValue());
logblock.saveConfig();
url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database");
url = "jdbc:mysql://" + config.getString("mysql.host") + ":" + config.getInt("mysql.port") + "/" + getStringIncludingInts(config, "mysql.database") + "?useUnicode=true&characterEncoding=utf-8";
user = getStringIncludingInts(config, "mysql.user");
password = getStringIncludingInts(config, "mysql.password");
delayBetweenRuns = config.getInt("consumer.delayBetweenRuns", 2);

View File

@@ -31,13 +31,14 @@ public class BlockBreakLogging extends LoggingListener
final String playerName = event.getPlayer().getName();
final Block origin = event.getBlock();
final int type = origin.getTypeId();
final int typeId = origin.getTypeId();
final Material type = origin.getType();
if (wcfg.isLogging(Logging.SIGNTEXT) && (type == 63 || type == 68)) {
if (wcfg.isLogging(Logging.SIGNTEXT) && (typeId == 63 || typeId == 68)) {
consumer.queueSignBreak(playerName, (Sign) origin.getState());
} else if (wcfg.isLogging(Logging.CHESTACCESS) && (type == 23 || type == 54 || type == 61)) {
} else if (wcfg.isLogging(Logging.CHESTACCESS) && BukkitUtils.getContainerBlocks().contains(type)) {
consumer.queueContainerBreak(playerName, origin.getState());
} else if (origin.getType() == Material.ICE) {
} else if (type == Material.ICE) {
// When in creative mode ice doesn't form water
if (event.getPlayer().getGameMode().equals(GameMode.CREATIVE)) {
consumer.queueBlockBreak(playerName, origin.getState());

View File

@@ -26,7 +26,7 @@ public class BlockPlaceLogging extends LoggingListener
public void onBlockPlace(BlockPlaceEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getBlock().getWorld());
if (wcfg != null && wcfg.isLogging(Logging.BLOCKPLACE)) {
final int type = event.getBlock().getTypeId();
final Material type = event.getBlock().getType();
final BlockState before = event.getBlockReplacedState();
final BlockState after = event.getBlockPlaced().getState();
final String playerName = event.getPlayer().getName();
@@ -53,11 +53,11 @@ public class BlockPlaceLogging extends LoggingListener
if (y != 0) {
Location finalLoc = new Location(loc.getWorld(), x, y, z);
// Run this check to avoid false positives
if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getTypeId())) {
if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) {
if (finalLoc.getBlock().getType() == Material.AIR || finalLoc.equals(event.getBlock().getLocation())) {
consumer.queueBlockPlace(playerName, finalLoc, type, event.getBlock().getData());
consumer.queueBlockPlace(playerName, finalLoc, type.getId(), event.getBlock().getData());
} else {
consumer.queueBlockReplace(playerName, finalLoc, finalLoc.getBlock().getTypeId(), finalLoc.getBlock().getData(), type, event.getBlock().getData());
consumer.queueBlockReplace(playerName, finalLoc, finalLoc.getBlock().getTypeId(), finalLoc.getBlock().getData(), type.getId(), event.getBlock().getData());
}
}
}
@@ -65,8 +65,7 @@ public class BlockPlaceLogging extends LoggingListener
}
//Sign logging is handled elsewhere
if (wcfg.isLogging(Logging.SIGNTEXT) && (type == 63 || type == 68))
return;
if (wcfg.isLogging(Logging.SIGNTEXT) && (type.getId() == 63 || type.getId() == 68)) return;
//Delay queuing by one tick to allow data to be updated
LogBlock.getInstance().getServer().getScheduler().scheduleSyncDelayedTask(LogBlock.getInstance(), new Runnable()

View File

@@ -0,0 +1,52 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.Material;
import org.bukkit.World;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.BlockSpreadEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class BlockSpreadLogging extends LoggingListener
{
public BlockSpreadLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockSpread(BlockSpreadEvent event) {
String name;
World world = event.getBlock().getWorld();
Material type = event.getSource().getType();
switch (type) {
case GRASS:
if (!isLogging(world, Logging.GRASSGROWTH)) return;
name = "GrassGrowth";
break;
case MYCEL:
if (!isLogging(world, Logging.MYCELIUMSPREAD)) return;
name = "MyceliumSpread";
break;
case VINE:
if (!isLogging(world, Logging.VINEGROWTH)) return;
name = "VineGrowth";
break;
case RED_MUSHROOM:
case BROWN_MUSHROOM:
if (!isLogging(world, Logging.MUSHROOMSPREAD)) return;
name = "MushroomSpread";
break;
default:
return;
}
consumer.queueBlockReplace(name, event.getBlock().getState(), event.getNewState());
}
}

View File

@@ -1,5 +1,6 @@
package de.diddiz.LogBlock.listeners;
import static de.diddiz.LogBlock.config.Config.isLogging;
import static de.diddiz.util.BukkitUtils.compareInventories;
import static de.diddiz.util.BukkitUtils.compressInventory;
import static de.diddiz.util.BukkitUtils.getInventoryHolderLocation;
@@ -7,6 +8,8 @@ import static de.diddiz.util.BukkitUtils.getInventoryHolderType;
import static de.diddiz.util.BukkitUtils.rawData;
import java.util.HashMap;
import java.util.Map;
import de.diddiz.LogBlock.Logging;
import org.bukkit.Location;
import org.bukkit.block.BlockState;
import org.bukkit.block.DoubleChest;
@@ -29,6 +32,8 @@ public class ChestAccessLogging extends LoggingListener
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryClose(InventoryCloseEvent event) {
if (!isLogging(event.getPlayer().getWorld(), Logging.CHESTACCESS)) return;
InventoryHolder holder = event.getInventory().getHolder();
if (holder instanceof BlockState || holder instanceof DoubleChest) {
final HumanEntity player = event.getPlayer();
@@ -47,6 +52,8 @@ public class ChestAccessLogging extends LoggingListener
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onInventoryOpen(InventoryOpenEvent event) {
if (!isLogging(event.getPlayer().getWorld(), Logging.CHESTACCESS)) return;
if (event.getInventory() != null) {
InventoryHolder holder = event.getInventory().getHolder();
if (holder instanceof BlockState || holder instanceof DoubleChest) {

View File

@@ -0,0 +1,57 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig;
import de.diddiz.util.BukkitUtils;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityInteractEvent;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
public class CreatureInteractLogging extends LoggingListener
{
public CreatureInteractLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityInteract(EntityInteractEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getEntity().getWorld());
final EntityType entityType = event.getEntityType();
// Mobs only
if (event.getEntity() instanceof Player || entityType == null) return;
if (wcfg != null) {
final Block clicked = event.getBlock();
final Material type = clicked.getType();
final int typeId = type.getId();
final byte blockData = clicked.getData();
final Location loc = clicked.getLocation();
switch (type) {
case SOIL:
if (wcfg.isLogging(Logging.CREATURECROPTRAMPLE)) {
// 3 = Dirt ID
consumer.queueBlock(entityType.getName(), loc, typeId, 3, blockData);
// Log the crop on top as being broken
Block trampledCrop = clicked.getRelative(BlockFace.UP);
if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) {
consumer.queueBlockBreak("CreatureTrample", trampledCrop.getState());
}
}
break;
}
}
}
}

View File

@@ -10,6 +10,7 @@ import org.bukkit.entity.EnderDragon;
import org.bukkit.entity.Entity;
import org.bukkit.entity.Fireball;
import org.bukkit.entity.Ghast;
import org.bukkit.entity.minecart.ExplosiveMinecart;
import org.bukkit.entity.Player;
import org.bukkit.entity.TNTPrimed;
import org.bukkit.entity.Wither;
@@ -31,25 +32,29 @@ public class ExplosionLogging extends LoggingListener
public void onEntityExplode(EntityExplodeEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getLocation().getWorld());
if (wcfg != null) {
String name = "Unknown";
if (event.getEntity() == null) {
String name = "Explosion";
Entity source = event.getEntity();
if (source == null) {
if (!wcfg.isLogging(Logging.MISCEXPLOSION))
return;
name = "Explosion";
} else if (event.getEntity() instanceof TNTPrimed) {
} else if (source instanceof TNTPrimed) {
if (!wcfg.isLogging(Logging.TNTEXPLOSION))
return;
name = "TNT";
} else if (event.getEntity() instanceof Creeper) {
} else if (source instanceof ExplosiveMinecart) {
if (!wcfg.isLogging(Logging.TNTMINECARTEXPLOSION))
return;
name = "TNTMinecart";
} else if (source instanceof Creeper) {
if (!wcfg.isLogging(Logging.CREEPEREXPLOSION))
return;
if (logCreeperExplosionsAsPlayerWhoTriggeredThese) {
final Entity target = ((Creeper)event.getEntity()).getTarget();
final Entity target = ((Creeper) source).getTarget();
name = target instanceof Player ? ((Player)target).getName() : "Creeper";
} else
name = "Creeper";
} else if (event.getEntity() instanceof Fireball) {
Fireball fireball = (Fireball) event.getEntity();
} else if (source instanceof Fireball) {
Fireball fireball = (Fireball) source;
Entity shooter = fireball.getShooter();
if (shooter == null) {
return;
@@ -65,22 +70,21 @@ public class ExplosionLogging extends LoggingListener
}
name = "Wither";
}
} else if (event.getEntity() instanceof EnderDragon) {
} else if (source instanceof EnderDragon) {
if (!wcfg.isLogging(Logging.ENDERDRAGON))
return;
name = "EnderDragon";
} else if (event.getEntity() instanceof Wither) {
} else if (source instanceof Wither) {
if(!wcfg.isLogging(Logging.WITHER))
return;
name = "Wither";
} else if (event.getEntity() instanceof WitherSkull) {
} else if (source instanceof WitherSkull) {
if(!wcfg.isLogging(Logging.WITHER_SKULL))
return;
name = "WitherSkull";
} else {
if (!wcfg.isLogging(Logging.MISCEXPLOSION))
return;
name = "Explosion";
}
for (final Block block : event.blockList()) {
final int type = block.getTypeId();

View File

@@ -1,8 +1,12 @@
package de.diddiz.LogBlock.listeners;
import static de.diddiz.LogBlock.config.Config.getWorldConfig;
import de.diddiz.util.BukkitUtils;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
import org.bukkit.block.BlockFace;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
@@ -21,34 +25,33 @@ public class InteractLogging extends LoggingListener
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld());
if (wcfg != null && (event.getAction() == Action.LEFT_CLICK_BLOCK || event.getAction() == Action.RIGHT_CLICK_BLOCK)) {
final Material type = event.getClickedBlock().getType();
if (wcfg != null) {
final Block clicked = event.getClickedBlock();
final Material type = clicked.getType();
final int typeId = type.getId();
final byte blockData = event.getClickedBlock().getData();
final byte blockData = clicked.getData();
final Player player = event.getPlayer();
final Location loc = event.getClickedBlock().getLocation();
final Location loc = clicked.getLocation();
switch (type) {
case LEVER:
case WOOD_BUTTON:
case STONE_BUTTON:
if (wcfg.isLogging(Logging.SWITCHINTERACT))
if (wcfg.isLogging(Logging.SWITCHINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK)
consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData);
break;
case FENCE_GATE:
if (event.getAction() != Action.RIGHT_CLICK_BLOCK)
break;
case WOODEN_DOOR:
case TRAP_DOOR:
if (wcfg.isLogging(Logging.DOORINTERACT))
if (wcfg.isLogging(Logging.DOORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK)
consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData);
break;
case CAKE_BLOCK:
if (wcfg.isLogging(Logging.CAKEEAT) && player.getFoodLevel() < 20)
if (wcfg.isLogging(Logging.CAKEEAT) && event.getAction() == Action.RIGHT_CLICK_BLOCK && player.getFoodLevel() < 20)
consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData);
break;
case NOTE_BLOCK:
if (wcfg.isLogging(Logging.NOTEBLOCKINTERACT))
if (wcfg.isLogging(Logging.NOTEBLOCKINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK)
consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData);
break;
case DIODE_BLOCK_OFF:
@@ -56,6 +59,36 @@ public class InteractLogging extends LoggingListener
if (wcfg.isLogging(Logging.DIODEINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK)
consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData);
break;
case REDSTONE_COMPARATOR_OFF:
case REDSTONE_COMPARATOR_ON:
if (wcfg.isLogging(Logging.COMPARATORINTERACT) && event.getAction() == Action.RIGHT_CLICK_BLOCK) {
consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData);
}
break;
case WOOD_PLATE:
case STONE_PLATE:
case IRON_PLATE:
case GOLD_PLATE:
if (wcfg.isLogging(Logging.PRESUREPLATEINTERACT) && event.getAction() == Action.PHYSICAL) {
consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData);
}
break;
case TRIPWIRE:
if (wcfg.isLogging(Logging.TRIPWIREINTERACT) && event.getAction() == Action.PHYSICAL) {
consumer.queueBlock(player.getName(), loc, typeId, typeId, blockData);
}
break;
case SOIL:
if (wcfg.isLogging(Logging.CROPTRAMPLE) && event.getAction() == Action.PHYSICAL) {
// 3 = Dirt ID
consumer.queueBlock(player.getName(), loc, typeId, 3, blockData);
// Log the crop on top as being broken
Block trampledCrop = clicked.getRelative(BlockFace.UP);
if (BukkitUtils.getCropBlocks().contains(trampledCrop.getType())) {
consumer.queueBlockBreak(player.getName(), trampledCrop.getState());
}
}
break;
}
}
}

View File

@@ -45,10 +45,15 @@ public class ToolListener implements Listener
final int type = event.getMaterial().getId();
final Tool tool = toolsByType.get(type);
final Player player = event.getPlayer();
if (tool != null && (action == Action.RIGHT_CLICK_BLOCK || action == Action.LEFT_CLICK_BLOCK) && isLogged(player.getWorld()) && logblock.hasPermission(player, "logblock.tools." + tool.name)) {
if (tool != null && (action == Action.RIGHT_CLICK_BLOCK || action == Action.LEFT_CLICK_BLOCK) && logblock.hasPermission(player, "logblock.tools." + tool.name)) {
final ToolBehavior behavior = action == Action.RIGHT_CLICK_BLOCK ? tool.rightClickBehavior : tool.leftClickBehavior;
final ToolData toolData = getSession(player).toolData.get(tool);
if (behavior != ToolBehavior.NONE && toolData.enabled) {
if (!isLogged(player.getWorld())) {
player.sendMessage(ChatColor.RED + "This world is not currently logged.");
event.setCancelled(true);
return;
}
final Block block = event.getClickedBlock();
final QueryParams params = toolData.params;
params.loc = null;

View File

@@ -32,6 +32,9 @@ public class BukkitUtils
private static final Set<Material> relativeTopFallables;
private static final Set<Material> fallingEntityKillers;
private static final Set<Material> cropBlocks;
private static final Set<Material> containerBlocks;
static {
blockEquivalents = new HashSet<Set<Integer>>(7);
blockEquivalents.add(new HashSet<Integer>(Arrays.asList(2, 3, 60)));
@@ -57,7 +60,7 @@ public class BukkitUtils
relativeBreakable.add(Material.COCOA);
// Blocks that break when they are on top of a block
relativeTopBreakable = new HashSet<Material>(26);
relativeTopBreakable = new HashSet<Material>(32);
relativeTopBreakable.add(Material.SAPLING);
relativeTopBreakable.add(Material.LONG_GRASS);
relativeTopBreakable.add(Material.DEAD_BUSH);
@@ -74,16 +77,22 @@ public class BukkitUtils
relativeTopBreakable.add(Material.FLOWER_POT);
relativeTopBreakable.add(Material.POWERED_RAIL);
relativeTopBreakable.add(Material.DETECTOR_RAIL);
relativeTopBreakable.add(Material.ACTIVATOR_RAIL);
relativeTopBreakable.add(Material.RAILS);
relativeTopBreakable.add(Material.REDSTONE_WIRE);
relativeTopBreakable.add(Material.SIGN_POST);
relativeTopBreakable.add(Material.STONE_PLATE);
relativeTopBreakable.add(Material.WOOD_PLATE);
relativeTopBreakable.add(Material.IRON_PLATE);
relativeTopBreakable.add(Material.GOLD_PLATE);
relativeTopBreakable.add(Material.SNOW);
relativeTopBreakable.add(Material.DIODE_BLOCK_ON);
relativeTopBreakable.add(Material.DIODE_BLOCK_OFF);
relativeTopBreakable.add(Material.REDSTONE_COMPARATOR_ON);
relativeTopBreakable.add(Material.REDSTONE_COMPARATOR_OFF);
relativeTopBreakable.add(Material.WOODEN_DOOR);
relativeTopBreakable.add(Material.IRON_DOOR);
relativeTopBreakable.add(Material.CARPET);
// Blocks that fall
relativeTopFallables = new HashSet<Material>(4);
@@ -93,9 +102,13 @@ public class BukkitUtils
relativeTopFallables.add(Material.ANVIL);
// Blocks that break falling entities
fallingEntityKillers = new HashSet<Material>(23);
fallingEntityKillers = new HashSet<Material>(32);
fallingEntityKillers.add(Material.SIGN_POST);
fallingEntityKillers.add(Material.WALL_SIGN);
fallingEntityKillers.add(Material.STONE_PLATE);
fallingEntityKillers.add(Material.WOOD_PLATE);
fallingEntityKillers.add(Material.IRON_PLATE);
fallingEntityKillers.add(Material.GOLD_PLATE);
fallingEntityKillers.add(Material.SAPLING);
fallingEntityKillers.add(Material.YELLOW_FLOWER);
fallingEntityKillers.add(Material.RED_ROSE);
@@ -110,6 +123,7 @@ public class BukkitUtils
fallingEntityKillers.add(Material.FLOWER_POT);
fallingEntityKillers.add(Material.POWERED_RAIL);
fallingEntityKillers.add(Material.DETECTOR_RAIL);
fallingEntityKillers.add(Material.ACTIVATOR_RAIL);
fallingEntityKillers.add(Material.RAILS);
fallingEntityKillers.add(Material.LEVER);
fallingEntityKillers.add(Material.REDSTONE_WIRE);
@@ -117,6 +131,29 @@ public class BukkitUtils
fallingEntityKillers.add(Material.REDSTONE_TORCH_OFF);
fallingEntityKillers.add(Material.DIODE_BLOCK_ON);
fallingEntityKillers.add(Material.DIODE_BLOCK_OFF);
fallingEntityKillers.add(Material.REDSTONE_COMPARATOR_ON);
fallingEntityKillers.add(Material.REDSTONE_COMPARATOR_OFF);
fallingEntityKillers.add(Material.DAYLIGHT_DETECTOR);
fallingEntityKillers.add(Material.CARPET);
// Crop Blocks
cropBlocks = new HashSet<Material>(5);
cropBlocks.add(Material.CROPS);
cropBlocks.add(Material.MELON_STEM);
cropBlocks.add(Material.PUMPKIN_STEM);
cropBlocks.add(Material.CARROT);
cropBlocks.add(Material.POTATO);
// Container Blocks
containerBlocks = new HashSet<Material>(6);
containerBlocks.add(Material.CHEST);
containerBlocks.add(Material.TRAPPED_CHEST);
containerBlocks.add(Material.DISPENSER);
containerBlocks.add(Material.DROPPER);
containerBlocks.add(Material.HOPPER);
containerBlocks.add(Material.BREWING_STAND);
// Doesn't actually have a block inventory
// containerBlocks.add(Material.ENDER_CHEST);
}
private static final BlockFace[] relativeBlockFaces = new BlockFace[] {
@@ -251,6 +288,14 @@ public class BukkitUtils
return fallingEntityKillers;
}
public static Set<Material> getCropBlocks() {
return cropBlocks;
}
public static Set<Material> getContainerBlocks() {
return containerBlocks;
}
public static String entityName(Entity entity) {
if (entity instanceof Player)
return ((Player)entity).getName();
@@ -319,7 +364,7 @@ public class BukkitUtils
return true;
} else if (mat == Material.WATER || mat == Material.STATIONARY_WATER || mat == Material.LAVA || mat == Material.STATIONARY_LAVA) { // Fluids
return true;
} else if (getFallingEntityKillers().contains(mat.getId()) || mat == Material.FIRE || mat == Material.VINE || mat == Material.LONG_GRASS || mat == Material.DEAD_BUSH) { // Misc.
} else if (getFallingEntityKillers().contains(mat) || mat == Material.FIRE || mat == Material.VINE || mat == Material.LONG_GRASS || mat == Material.DEAD_BUSH) { // Misc.
return true;
}
return false;

View File

@@ -32,7 +32,7 @@ public class LoggingUtil {
Block checkBlock = origin.getRelative(BlockFace.UP);
int up = 0;
final int highestBlock = checkBlock.getWorld().getHighestBlockYAt(checkBlock.getLocation());
while (BukkitUtils.getRelativeTopFallables().contains(checkBlock.getTypeId())) {
while (BukkitUtils.getRelativeTopFallables().contains(checkBlock.getType())) {
// Record this block as falling
consumer.queueBlockBreak(playerName, checkBlock.getState());
@@ -49,9 +49,9 @@ public class LoggingUtil {
if (y != 0) {
Location finalLoc = new Location(loc.getWorld(), x, y, z);
// Run this check to avoid false positives
if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getTypeId())) {
if (!BukkitUtils.getFallingEntityKillers().contains(finalLoc.getBlock().getType())) {
finalLoc.add(0, up, 0); // Add this here after checking for block breakers
if (finalLoc.getBlock().getType() == Material.AIR || BukkitUtils.getRelativeTopFallables().contains(finalLoc.getBlock().getTypeId())) {
if (finalLoc.getBlock().getType() == Material.AIR || BukkitUtils.getRelativeTopFallables().contains(finalLoc.getBlock().getType())) {
consumer.queueBlockPlace(playerName, finalLoc, checkBlock.getTypeId(), checkBlock.getData());
} else {
consumer.queueBlockReplace(playerName, finalLoc, finalLoc.getBlock().getTypeId(), finalLoc.getBlock().getData(), checkBlock.getTypeId(), checkBlock.getData());
@@ -70,9 +70,21 @@ public class LoggingUtil {
if (wcfg == null) return;
Block checkBlock = origin.getRelative(BlockFace.UP);
if (BukkitUtils.getRelativeTopBreakabls().contains(checkBlock.getTypeId())) {
if (BukkitUtils.getRelativeTopBreakabls().contains(checkBlock.getType())) {
if (wcfg.isLogging(Logging.SIGNTEXT) && checkBlock.getType() == Material.SIGN_POST) {
consumer.queueSignBreak(playerName, (Sign) checkBlock.getState());
} else if (checkBlock.getType() == Material.IRON_DOOR || checkBlock.getType() == Material.WOOD_DOOR) {
Block doorBlock = checkBlock;
// If the doorBlock is the top half a door the player simply punched a door
// this will be handled later.
if (doorBlock.getData() != 8 && doorBlock.getData() != 9) {
doorBlock = doorBlock.getRelative(BlockFace.UP);
// Fall back check just in case the top half wasn't a door
if (doorBlock.getType() == Material.IRON_DOOR || doorBlock.getType() == Material.WOOD_DOOR) {
consumer.queueBlockBreak(playerName, doorBlock.getState());
}
consumer.queueBlockBreak(playerName, checkBlock.getState());
}
} else {
consumer.queueBlockBreak(playerName, checkBlock.getState());
}
@@ -142,6 +154,23 @@ public class LoggingUtil {
}
}
}
// Special door check
if (origin.getType() == Material.IRON_DOOR || origin.getType() == Material.WOOD_DOOR) {
Block doorBlock = origin;
// Up or down?
if (origin.getData() != 8 && origin.getData() != 9) {
doorBlock = doorBlock.getRelative(BlockFace.UP);
} else {
doorBlock = doorBlock.getRelative(BlockFace.DOWN);
}
if (doorBlock.getType() == Material.IRON_DOOR || doorBlock.getType() == Material.WOOD_DOOR) {
consumer.queueBlockBreak(playerName, doorBlock.getState());
}
}
// Do this down here so that the block is added after blocks sitting on it
consumer.queueBlockBreak(playerName, origin.getState());
}