forked from LogBlock/LogBlock
Serialize BlockStates
Banner, spawner and player heads can now be rolled back
This commit is contained in:
2
pom.xml
2
pom.xml
@ -4,7 +4,7 @@
|
||||
|
||||
<groupId>de.diddiz</groupId>
|
||||
<artifactId>logblock</artifactId>
|
||||
<version>1.13-SNAPSHOT</version>
|
||||
<version>1.13.1-SNAPSHOT</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>LogBlock</name>
|
||||
|
@ -1,5 +1,6 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import de.diddiz.LogBlock.blockstate.BlockStateCodecs;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
import de.diddiz.util.Utils;
|
||||
@ -14,29 +15,28 @@ import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import static de.diddiz.util.LoggingUtil.checkText;
|
||||
import java.util.logging.Level;
|
||||
|
||||
public class BlockChange implements LookupCacheElement {
|
||||
public final long id, date;
|
||||
public final Location loc;
|
||||
public final Actor actor;
|
||||
public final String playerName;
|
||||
// public final BlockData replaced, type;
|
||||
public final int replacedMaterial, replacedData, typeMaterial, typeData;
|
||||
public final String signtext;
|
||||
public final byte[] replacedState, typeState;
|
||||
public final ChestAccess ca;
|
||||
|
||||
public BlockChange(long date, Location loc, Actor actor, int replaced, int replacedData, int type, int typeData, String signtext, ChestAccess ca) {
|
||||
public BlockChange(long date, Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) {
|
||||
id = 0;
|
||||
this.date = date;
|
||||
this.loc = loc;
|
||||
this.actor = actor;
|
||||
this.replacedMaterial = replaced;
|
||||
this.replacedData = replacedData;
|
||||
this.replacedState = replacedState;
|
||||
this.typeMaterial = type;
|
||||
this.typeData = typeData;
|
||||
this.signtext = checkText(signtext);
|
||||
this.typeState = typeState;
|
||||
this.ca = ca;
|
||||
this.playerName = actor == null ? null : actor.getName();
|
||||
}
|
||||
@ -51,7 +51,8 @@ public class BlockChange implements LookupCacheElement {
|
||||
replacedData = p.needType ? rs.getInt("replacedData") : -1;
|
||||
typeMaterial = p.needType ? rs.getInt("type") : 0;
|
||||
typeData = p.needType ? rs.getInt("typeData") : -1;
|
||||
signtext = p.needSignText ? rs.getString("signtext") : null;
|
||||
replacedState = p.needType ? rs.getBytes("replacedState") : null;
|
||||
typeState = p.needType ? rs.getBytes("typeState") : null;
|
||||
ChestAccess catemp = null;
|
||||
if (p.needChestAccess) {
|
||||
ItemStack stack = Utils.loadItemStack(rs.getBytes("item"));
|
||||
@ -66,6 +67,32 @@ public class BlockChange implements LookupCacheElement {
|
||||
public String toString() {
|
||||
BlockData type = MaterialConverter.getBlockData(typeMaterial, typeData);
|
||||
BlockData replaced = MaterialConverter.getBlockData(replacedMaterial, replacedData);
|
||||
String typeDetails = null;
|
||||
if (BlockStateCodecs.hasCodec(type.getMaterial())) {
|
||||
try {
|
||||
typeDetails = BlockStateCodecs.toString(type.getMaterial(), typeState);
|
||||
} catch (Exception e) {
|
||||
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + type.getMaterial(), e);
|
||||
}
|
||||
}
|
||||
if (typeDetails == null) {
|
||||
typeDetails = "";
|
||||
} else {
|
||||
typeDetails = " " + typeDetails;
|
||||
}
|
||||
String replacedDetails = null;
|
||||
if (BlockStateCodecs.hasCodec(replaced.getMaterial())) {
|
||||
try {
|
||||
replacedDetails = BlockStateCodecs.toString(replaced.getMaterial(), replacedState);
|
||||
} catch (Exception e) {
|
||||
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Could not parse BlockState for " + replaced.getMaterial(), e);
|
||||
}
|
||||
}
|
||||
if (replacedDetails == null) {
|
||||
replacedDetails = "";
|
||||
} else {
|
||||
replacedDetails = " " + replacedDetails;
|
||||
}
|
||||
final StringBuilder msg = new StringBuilder();
|
||||
if (date > 0) {
|
||||
msg.append(Config.formatter.format(date)).append(" ");
|
||||
@ -73,14 +100,7 @@ public class BlockChange implements LookupCacheElement {
|
||||
if (actor != null) {
|
||||
msg.append(actor.getName()).append(" ");
|
||||
}
|
||||
if (signtext != null) {
|
||||
final String action = BukkitUtils.isEmpty(type.getMaterial()) ? "destroyed " : "created ";
|
||||
if (!signtext.contains("\0")) {
|
||||
msg.append(action).append(signtext);
|
||||
} else {
|
||||
msg.append(action).append((!BukkitUtils.isEmpty(type.getMaterial()) ? type : replaced).getMaterial().name()).append(" [").append(signtext.replace("\0", "] [")).append("]");
|
||||
}
|
||||
} else if (type.equals(replaced)) {
|
||||
if (type.equals(replaced)) {
|
||||
if (BukkitUtils.isEmpty(type.getMaterial())) {
|
||||
msg.append("did an unspecified action");
|
||||
} else if (ca != null) {
|
||||
@ -110,11 +130,11 @@ public class BlockChange implements LookupCacheElement {
|
||||
msg.append("ran into ").append(type.getMaterial().name());
|
||||
}
|
||||
} else if (BukkitUtils.isEmpty(type.getMaterial())) {
|
||||
msg.append("destroyed ").append(replaced.getMaterial().name());
|
||||
msg.append("destroyed ").append(replaced.getMaterial().name()).append(replacedDetails);
|
||||
} else if (BukkitUtils.isEmpty(replaced.getMaterial())) {
|
||||
msg.append("created ").append(type.getMaterial().name());
|
||||
msg.append("created ").append(type.getMaterial().name()).append(typeDetails);
|
||||
} else {
|
||||
msg.append("replaced ").append(replaced.getMaterial().name()).append(" with ").append(type.getMaterial().name());
|
||||
msg.append("replaced ").append(replaced.getMaterial().name()).append(replacedDetails).append(" with ").append(type.getMaterial().name()).append(typeDetails);
|
||||
}
|
||||
if (loc != null) {
|
||||
msg.append(" at ").append(loc.getBlockX()).append(":").append(loc.getBlockY()).append(":").append(loc.getBlockZ());
|
||||
|
@ -10,7 +10,6 @@ import de.diddiz.util.Utils;
|
||||
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.command.Command;
|
||||
import org.bukkit.command.CommandExecutor;
|
||||
@ -456,9 +455,6 @@ public class CommandsHandler implements CommandExecutor {
|
||||
params.needType = true;
|
||||
params.needData = true;
|
||||
params.needPlayer = true;
|
||||
if (params.types.isEmpty() || params.types.contains(Material.SIGN) || params.types.contains(Material.WALL_SIGN)) {
|
||||
params.needSignText = true;
|
||||
}
|
||||
if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) {
|
||||
params.needChestAccess = true;
|
||||
}
|
||||
@ -521,9 +517,6 @@ public class CommandsHandler implements CommandExecutor {
|
||||
params.needType = true;
|
||||
params.needData = true;
|
||||
params.needPlayer = true;
|
||||
if (params.types.isEmpty() || params.types.contains(Material.SIGN) || params.types.contains(Material.WALL_SIGN)) {
|
||||
params.needSignText = true;
|
||||
}
|
||||
if (params.bct == BlockChangeType.CHESTACCESS || params.bct == BlockChangeType.ALL) {
|
||||
params.needChestAccess = true;
|
||||
}
|
||||
@ -646,7 +639,6 @@ public class CommandsHandler implements CommandExecutor {
|
||||
params.needCoords = true;
|
||||
params.needType = true;
|
||||
params.needData = true;
|
||||
params.needSignText = true;
|
||||
params.needChestAccess = true;
|
||||
params.order = Order.DESC;
|
||||
params.sum = SummarizationMode.NONE;
|
||||
@ -674,7 +666,7 @@ public class CommandsHandler implements CommandExecutor {
|
||||
if (stack != null) {
|
||||
chestaccess = new ChestAccess(stack, rs.getBoolean("itemremove"));
|
||||
}
|
||||
editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getInt("type"), rs.getInt("typeData"), rs.getString("signtext"), chestaccess);
|
||||
editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), chestaccess);
|
||||
}
|
||||
final int changes = editor.getSize();
|
||||
if (changes > 10000) {
|
||||
@ -725,7 +717,6 @@ public class CommandsHandler implements CommandExecutor {
|
||||
params.needCoords = true;
|
||||
params.needType = true;
|
||||
params.needData = true;
|
||||
params.needSignText = true;
|
||||
params.needChestAccess = true;
|
||||
params.order = Order.ASC;
|
||||
params.sum = SummarizationMode.NONE;
|
||||
@ -749,7 +740,7 @@ public class CommandsHandler implements CommandExecutor {
|
||||
if (stack != null) {
|
||||
chestaccess = new ChestAccess(stack, !rs.getBoolean("itemremove"));
|
||||
}
|
||||
editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getString("signtext"), chestaccess);
|
||||
editor.queueEdit(rs.getInt("x"), rs.getInt("y"), rs.getInt("z"), rs.getInt("type"), rs.getInt("typeData"), rs.getBytes("typeState"), rs.getInt("replaced"), rs.getInt("replacedData"), rs.getBytes("replacedState"), chestaccess);
|
||||
}
|
||||
final int changes = editor.getSize();
|
||||
if (!params.silent) {
|
||||
@ -824,23 +815,23 @@ public class CommandsHandler implements CommandExecutor {
|
||||
state.execute("DELETE `" + table + "` FROM `" + table + "-blocks` " + join + params.getWhere());
|
||||
sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + ". Deleted " + deleted + " entries.");
|
||||
}
|
||||
rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-sign` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL");
|
||||
rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-state` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL");
|
||||
rs.next();
|
||||
if ((deleted = rs.getInt(1)) > 0) {
|
||||
if (dumpDeletedLog) {
|
||||
state.execute("SELECT id, signtext FROM `" + table + "-sign` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-sign " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'");
|
||||
state.execute("SELECT id, replacedState, typeState FROM `" + table + "-state` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-state " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'");
|
||||
}
|
||||
state.execute("DELETE `" + table + "-sign` FROM `" + table + "-sign` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL;");
|
||||
sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-sign. Deleted " + deleted + " entries.");
|
||||
state.execute("DELETE `" + table + "-state` FROM `" + table + "-state` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL;");
|
||||
sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-state. Deleted " + deleted + " entries.");
|
||||
}
|
||||
rs = state.executeQuery("SELECT COUNT(*) FROM `" + table + "-chestdata` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL");
|
||||
rs.next();
|
||||
if ((deleted = rs.getInt(1)) > 0) {
|
||||
if (dumpDeletedLog) {
|
||||
state.execute("SELECT id, item, itemremove FROM `" + table + "-chest` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-chest " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'");
|
||||
state.execute("SELECT id, item, itemremove FROM `" + table + "-chestdata` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL INTO OUTFILE '" + new File(dumpFolder, time + " " + table + "-chest " + params.getTitle() + ".csv").getAbsolutePath().replace("\\", "\\\\") + "' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '\"' LINES TERMINATED BY '\n'");
|
||||
}
|
||||
state.execute("DELETE `" + table + "-chest` FROM `" + table + "-chest` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL;");
|
||||
sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-chest. Deleted " + deleted + " entries.");
|
||||
state.execute("DELETE `" + table + "-chestdata` FROM `" + table + "-chestdata` LEFT JOIN `" + table + "-blocks` USING (id) WHERE `" + table + "-blocks`.id IS NULL;");
|
||||
sender.sendMessage(ChatColor.GREEN + "Cleared out table " + table + "-chestdata. Deleted " + deleted + " entries.");
|
||||
}
|
||||
} catch (final Exception ex) {
|
||||
sender.sendMessage(ChatColor.RED + "Exception, check error log");
|
||||
|
@ -1,5 +1,7 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import de.diddiz.LogBlock.blockstate.BlockStateCodecSign;
|
||||
import de.diddiz.LogBlock.blockstate.BlockStateCodecs;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import de.diddiz.LogBlock.events.BlockChangePreLogEvent;
|
||||
import de.diddiz.util.Utils;
|
||||
@ -63,7 +65,7 @@ public class Consumer extends TimerTask {
|
||||
* Data of the block after the change
|
||||
*/
|
||||
public void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter) {
|
||||
queueBlock(actor, loc, typeBefore, typeAfter, null, null);
|
||||
queueBlock(actor, loc, typeBefore, typeAfter, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -75,7 +77,7 @@ public class Consumer extends TimerTask {
|
||||
* Blockstate of the block before actually being destroyed.
|
||||
*/
|
||||
public void queueBlockBreak(Actor actor, BlockState before) {
|
||||
queueBlockBreak(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData());
|
||||
queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), null, BlockStateCodecs.serialize(before), null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -103,7 +105,7 @@ public class Consumer extends TimerTask {
|
||||
* Blockstate of the block after actually being placed.
|
||||
*/
|
||||
public void queueBlockPlace(Actor actor, BlockState after) {
|
||||
queueBlockPlace(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), after.getBlockData());
|
||||
queueBlock(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), null, after.getBlockData(), null, BlockStateCodecs.serialize(after), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -133,7 +135,7 @@ public class Consumer extends TimerTask {
|
||||
* Blockstate of the block after actually being placed.
|
||||
*/
|
||||
public void queueBlockReplace(Actor actor, BlockState before, BlockState after) {
|
||||
queueBlockReplace(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), after.getBlockData());
|
||||
queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), after.getBlockData(), BlockStateCodecs.serialize(before), BlockStateCodecs.serialize(after), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -149,7 +151,7 @@ public class Consumer extends TimerTask {
|
||||
* Data of the block after being replaced
|
||||
*/
|
||||
public void queueBlockReplace(Actor actor, BlockState before, BlockData typeAfter) {
|
||||
queueBlockReplace(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), typeAfter);
|
||||
queueBlock(actor, new Location(before.getWorld(), before.getX(), before.getY(), before.getZ()), before.getBlockData(), typeAfter, BlockStateCodecs.serialize(before), null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -165,12 +167,11 @@ public class Consumer extends TimerTask {
|
||||
* Blockstate of the block after actually being placed.
|
||||
*/
|
||||
public void queueBlockReplace(Actor actor, BlockData typeBefore, BlockState after) {
|
||||
queueBlockReplace(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), typeBefore, after.getBlockData());
|
||||
queueBlock(actor, new Location(after.getWorld(), after.getX(), after.getY(), after.getZ()), typeBefore, after.getBlockData(), null, BlockStateCodecs.serialize(after), null);
|
||||
}
|
||||
|
||||
public void queueBlockReplace(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter) {
|
||||
queueBlockBreak(actor, loc, typeBefore);
|
||||
queueBlockPlace(actor, loc, typeAfter);
|
||||
queueBlock(actor, loc, typeBefore, typeAfter, null, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -211,7 +212,7 @@ public class Consumer extends TimerTask {
|
||||
* Data of the item taken/stored
|
||||
*/
|
||||
public void queueChestAccess(Actor actor, Location loc, BlockData type, ItemStack itemStack, boolean remove) {
|
||||
queueBlock(actor, loc, type, type, null, new ChestAccess(itemStack, remove));
|
||||
queueBlock(actor, loc, type, type, null, null, new ChestAccess(itemStack, remove));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -326,11 +327,8 @@ public class Consumer extends TimerTask {
|
||||
* @param lines
|
||||
* The four lines on the sign.
|
||||
*/
|
||||
public void queueSignBreak(Actor actor, Location loc, BlockData type, String[] lines) {
|
||||
if ((type.getMaterial() != Material.SIGN && type.getMaterial() != Material.WALL_SIGN) || lines == null || lines.length != 4) {
|
||||
return;
|
||||
}
|
||||
queueBlock(actor, loc, type, null, lines[0] + "\0" + lines[1] + "\0" + lines[2] + "\0" + lines[3], null);
|
||||
public void queueSignBreak(Actor actor, Location loc, BlockData type, byte[] typeState) {
|
||||
queueBlock(actor, loc, type, null, typeState, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -342,7 +340,7 @@ public class Consumer extends TimerTask {
|
||||
* The sign being broken
|
||||
*/
|
||||
public void queueSignBreak(Actor actor, Sign sign) {
|
||||
queueSignBreak(actor, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getBlockData(), sign.getLines());
|
||||
queueSignBreak(actor, new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()), sign.getBlockData(), BlockStateCodecs.serialize(sign));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -363,7 +361,7 @@ public class Consumer extends TimerTask {
|
||||
if ((type.getMaterial() != Material.SIGN && type.getMaterial() != Material.WALL_SIGN) || lines == null || lines.length != 4) {
|
||||
return;
|
||||
}
|
||||
queueBlock(actor, loc, null, type, lines[0] + "\0" + lines[1] + "\0" + lines[2] + "\0" + lines[3], null);
|
||||
queueBlock(actor, loc, null, type, null, Utils.serializeYamlConfiguration(BlockStateCodecSign.serialize(lines)), null);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -585,7 +583,7 @@ public class Consumer extends TimerTask {
|
||||
return playerIds.containsKey(actor);
|
||||
}
|
||||
|
||||
private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter, String signtext, ChestAccess ca) {
|
||||
private void queueBlock(Actor actor, Location loc, BlockData typeBefore, BlockData typeAfter, byte[] stateBefore, byte[] stateAfter, ChestAccess ca) {
|
||||
if (typeBefore == null) {
|
||||
typeBefore = Bukkit.createBlockData(Material.AIR);
|
||||
}
|
||||
@ -594,7 +592,7 @@ public class Consumer extends TimerTask {
|
||||
}
|
||||
if (Config.fireCustomEvents) {
|
||||
// Create and call the event
|
||||
BlockChangePreLogEvent event = new BlockChangePreLogEvent(actor, loc, typeBefore, typeAfter, signtext, ca);
|
||||
BlockChangePreLogEvent event = new BlockChangePreLogEvent(actor, loc, typeBefore, typeAfter, null, ca);
|
||||
logblock.getServer().getPluginManager().callEvent(event);
|
||||
if (event.isCancelled()) {
|
||||
return;
|
||||
@ -605,7 +603,7 @@ public class Consumer extends TimerTask {
|
||||
loc = event.getLocation();
|
||||
typeBefore = event.getTypeBefore();
|
||||
typeAfter = event.getTypeAfter();
|
||||
signtext = event.getSignText();
|
||||
// signtext = event.getSignText();
|
||||
ca = event.getChestAccess();
|
||||
}
|
||||
// Do this last so LogBlock still has final say in what is being added
|
||||
@ -620,7 +618,7 @@ public class Consumer extends TimerTask {
|
||||
int typeMaterialId = MaterialConverter.getOrAddMaterialId(typeString);
|
||||
int typeStateId = MaterialConverter.getOrAddBlockStateId(typeString);
|
||||
|
||||
queue.add(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, typeMaterialId, typeStateId, signtext, ca));
|
||||
queue.add(new BlockRow(loc, actor, replacedMaterialId, replacedStateId, stateBefore, typeMaterialId, typeStateId, stateAfter, ca));
|
||||
}
|
||||
|
||||
private String playerID(Actor actor) {
|
||||
@ -670,19 +668,19 @@ public class Consumer extends TimerTask {
|
||||
private class BlockRow extends BlockChange implements MergeableRow {
|
||||
private Connection connection;
|
||||
|
||||
public BlockRow(Location loc, Actor actor, int replaced, int replacedData, int type, int typeData, String signtext, ChestAccess ca) {
|
||||
super(System.currentTimeMillis() / 1000, loc, actor, replaced, replacedData, type, typeData, signtext, ca);
|
||||
public BlockRow(Location loc, Actor actor, int replaced, int replacedData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) {
|
||||
super(System.currentTimeMillis() / 1000, loc, actor, replaced, replacedData, replacedState, type, typeData, typeState, ca);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getInserts() {
|
||||
final String table = getWorldConfig(loc.getWorld()).table;
|
||||
final String[] inserts = new String[ca != null || signtext != null ? 2 : 1];
|
||||
final String[] inserts = new String[ca != null || replacedState != null || typeState != null ? 2 : 1];
|
||||
|
||||
inserts[0] = "INSERT INTO `" + table + "-blocks` (date, playerid, replaced, replaceddata, type, typedata, x, y, z) VALUES (FROM_UNIXTIME(" + date + "), " + playerID(actor) + ", " + replacedMaterial + ", " + replacedData + ", " + typeMaterial + ", " + typeData + ", '" + loc.getBlockX()
|
||||
+ "', " + safeY(loc) + ", '" + loc.getBlockZ() + "');";
|
||||
if (signtext != null) {
|
||||
inserts[1] = "INSERT INTO `" + table + "-sign` (id, signtext) values (LAST_INSERT_ID(), '" + mysqlTextEscape(signtext) + "');";
|
||||
if (replacedState != null || typeState != null) {
|
||||
inserts[1] = "INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES('" + Utils.mysqlEscapeBytes(replacedState) + "', '" + Utils.mysqlEscapeBytes(typeState) + "', LAST_INSERT_ID());";
|
||||
} else if (ca != null) {
|
||||
inserts[1] = "INSERT INTO `" + table + "-chestdata` (id, item, itemremoved) values (LAST_INSERT_ID(), '" + Utils.mysqlEscapeBytes(Utils.saveItemStack(ca.itemStack)) + "', " + (ca.remove ? 1 : 0) + ");";
|
||||
}
|
||||
@ -727,10 +725,11 @@ public class Consumer extends TimerTask {
|
||||
rs.next();
|
||||
id = rs.getInt(1);
|
||||
|
||||
if (signtext != null) {
|
||||
ps = connection.prepareStatement("INSERT INTO `" + table + "-sign` (signtext, id) VALUES(?, ?)");
|
||||
ps.setString(1, signtext);
|
||||
ps.setInt(2, id);
|
||||
if (typeState != null || replacedState != null) {
|
||||
ps = connection.prepareStatement("INSERT INTO `" + table + "-state` (replacedState, typeState, id) VALUES(?, ?, ?)");
|
||||
ps.setBytes(1, replacedState);
|
||||
ps.setBytes(2, typeState);
|
||||
ps.setInt(3, id);
|
||||
ps.executeUpdate();
|
||||
} else if (ca != null) {
|
||||
ps = connection.prepareStatement("INSERT INTO `" + table + "-chestdata` (item, itemremove, id) values (?, ?, ?)");
|
||||
@ -772,7 +771,7 @@ public class Consumer extends TimerTask {
|
||||
|
||||
@Override
|
||||
public boolean isUnique() {
|
||||
return !(signtext == null && ca == null && playerIds.containsKey(actor));
|
||||
return !(typeState == null && replacedState == null && ca == null && playerIds.containsKey(actor));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -34,7 +34,7 @@ public final class QueryParams implements Cloneable {
|
||||
public List<Integer> typeIds = new ArrayList<Integer>();
|
||||
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, needKiller = false, needVictim = false, needWeapon = false;
|
||||
public boolean needCount = false, needId = false, needDate = false, needType = false, needData = false, needPlayer = false, needCoords = false, needChestAccess = false, needMessage = false, needKiller = false, needVictim = false, needWeapon = false;
|
||||
private final LogBlock logblock;
|
||||
|
||||
public QueryParams(LogBlock logblock) {
|
||||
@ -145,8 +145,8 @@ public final class QueryParams implements Cloneable {
|
||||
if (needCoords) {
|
||||
select += "x, y, z, ";
|
||||
}
|
||||
if (needSignText) {
|
||||
select += "signtext, ";
|
||||
if (needData) {
|
||||
select += "replacedState, typeState, ";
|
||||
}
|
||||
if (needChestAccess) {
|
||||
select += "item, itemremove, ";
|
||||
@ -157,8 +157,8 @@ public final class QueryParams implements Cloneable {
|
||||
if (needPlayer || players.size() > 0) {
|
||||
from += "INNER JOIN `lb-players` USING (playerid) ";
|
||||
}
|
||||
if (needSignText) {
|
||||
from += "LEFT JOIN `" + getTable() + "-sign` USING (id) ";
|
||||
if (!needCount && needData) {
|
||||
from += "LEFT JOIN `" + getTable() + "-state` USING (id) ";
|
||||
}
|
||||
if (needChestAccess)
|
||||
// If BlockChangeType is CHESTACCESS, we can use more efficient query
|
||||
|
@ -1,5 +1,6 @@
|
||||
package de.diddiz.LogBlock;
|
||||
|
||||
import de.diddiz.LogBlock.blockstate.BlockStateCodecSign;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import de.diddiz.LogBlock.config.WorldConfig;
|
||||
import de.diddiz.util.UUIDFetcher;
|
||||
@ -386,7 +387,7 @@ class Updater {
|
||||
}
|
||||
for (final WorldConfig wcfg : getLoggedWorlds()) {
|
||||
if (wcfg.isLogging(Logging.SIGNTEXT)) {
|
||||
checkCharset(wcfg.table + "-sign","signtext",st);
|
||||
// checkCharset(wcfg.table + "-sign","signtext",st);
|
||||
}
|
||||
}
|
||||
st.close();
|
||||
@ -565,7 +566,7 @@ class Updater {
|
||||
}
|
||||
rs.close();
|
||||
|
||||
PreparedStatement updateWeaponStatement = conn.prepareStatement("UPDATE `" + wcfg.table + "`-kills SET weapon = ? WHERE id = ?");
|
||||
PreparedStatement updateWeaponStatement = conn.prepareStatement("UPDATE `" + wcfg.table + "-kills` SET weapon = ? WHERE id = ?");
|
||||
for (int start = 0;; start += 10000) {
|
||||
rs = st.executeQuery("SELECT id, weapon FROM `" + wcfg.table + "-kills` ORDER BY id ASC LIMIT " + start + ",10000");
|
||||
boolean anyUpdate = false;
|
||||
@ -622,7 +623,85 @@ class Updater {
|
||||
}
|
||||
config.set("version", "1.13.0");
|
||||
}
|
||||
|
||||
if (configVersion.compareTo(new ComparableVersion("1.13.1")) < 0) {
|
||||
getLogger().info("Updating tables to 1.13.1 ...");
|
||||
try {
|
||||
final Connection conn = logblock.getConnection();
|
||||
conn.setAutoCommit(false);
|
||||
final Statement st = conn.createStatement();
|
||||
for (final WorldConfig wcfg : getLoggedWorlds()) {
|
||||
getLogger().info("Processing world " + wcfg.world + "...");
|
||||
if (wcfg.isLogging(Logging.SIGNTEXT)) {
|
||||
int rowsToConvert = 0;
|
||||
int done = 0;
|
||||
try {
|
||||
ResultSet rs = st.executeQuery("SELECT count(*) as rowcount FROM `" + wcfg.table + "-sign`");
|
||||
if (rs.next()) {
|
||||
rowsToConvert = rs.getInt(1);
|
||||
getLogger().info("Converting " + rowsToConvert + " entries in " + wcfg.table + "-sign");
|
||||
}
|
||||
rs.close();
|
||||
|
||||
PreparedStatement insertSignState = conn.prepareStatement("INSERT INTO `" + wcfg.table + "-state` (id, replacedState, typeState) VALUES (?, ?, ?)");
|
||||
PreparedStatement deleteSign = conn.prepareStatement("DELETE FROM `" + wcfg.table + "-sign` WHERE id = ?");
|
||||
while (true) {
|
||||
rs = st.executeQuery("SELECT id, signtext, replaced, type FROM `" + wcfg.table + "-sign` LEFT JOIN `" + wcfg.table + "-blocks` USING (id) ORDER BY id ASC LIMIT 10000");
|
||||
boolean anyRow = false;
|
||||
while (rs.next()) {
|
||||
anyRow = true;
|
||||
int id = rs.getInt("id");
|
||||
String signText = rs.getString("signtext");
|
||||
int replaced = rs.getInt("replaced");
|
||||
boolean nullBlock = rs.wasNull();
|
||||
int type = rs.getInt("type");
|
||||
|
||||
if (!nullBlock && signText != null) {
|
||||
String[] lines = signText.split("\0", 4);
|
||||
byte[] bytes = Utils.serializeYamlConfiguration(BlockStateCodecSign.serialize(lines));
|
||||
|
||||
Material replacedMaterial = MaterialConverter.getBlockData(replaced, -1).getMaterial();
|
||||
Material typeMaterial = MaterialConverter.getBlockData(type, -1).getMaterial();
|
||||
boolean wasSign = replacedMaterial == Material.SIGN || replacedMaterial == Material.WALL_SIGN;
|
||||
boolean isSign = typeMaterial == Material.SIGN || typeMaterial == Material.WALL_SIGN;
|
||||
|
||||
insertSignState.setInt(1, id);
|
||||
insertSignState.setBytes(2, wasSign ? bytes : null);
|
||||
insertSignState.setBytes(3, isSign ? bytes : null);
|
||||
insertSignState.addBatch();
|
||||
}
|
||||
|
||||
deleteSign.setInt(1, id);
|
||||
deleteSign.addBatch();
|
||||
done++;
|
||||
}
|
||||
rs.close();
|
||||
if (!anyRow) {
|
||||
break;
|
||||
}
|
||||
insertSignState.executeBatch();
|
||||
deleteSign.executeBatch();
|
||||
conn.commit();
|
||||
getLogger().info("Done: " + done + "/" + rowsToConvert + " (" + (rowsToConvert > 0 ? (done * 100 / rowsToConvert) : 100) + "%)");
|
||||
}
|
||||
insertSignState.close();
|
||||
deleteSign.close();
|
||||
} catch (SQLException e) {
|
||||
getLogger().info("Could not convert " + wcfg.table + "-sign: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
st.close();
|
||||
conn.close();
|
||||
} catch (final SQLException ex) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "[Updater] Error: ", ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
config.set("version", "1.13.1");
|
||||
}
|
||||
|
||||
logblock.saveConfig();
|
||||
return true;
|
||||
}
|
||||
@ -667,8 +746,9 @@ class Updater {
|
||||
|
||||
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 + "-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, 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))");
|
||||
}
|
||||
|
@ -7,7 +7,6 @@ import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockFace;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.data.Bisected.Half;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
import org.bukkit.block.data.type.Bed;
|
||||
@ -20,6 +19,7 @@ import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.inventory.InventoryHolder;
|
||||
import org.bukkit.inventory.ItemStack;
|
||||
|
||||
import de.diddiz.LogBlock.blockstate.BlockStateCodecs;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
|
||||
import java.io.File;
|
||||
@ -76,8 +76,8 @@ public class WorldEditor implements Runnable {
|
||||
this.sender = sender;
|
||||
}
|
||||
|
||||
public void queueEdit(int x, int y, int z, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess item) {
|
||||
edits.add(new Edit(0, new Location(world, x, y, z), null, replaced, replaceData, type, typeData, signtext, item));
|
||||
public void queueEdit(int x, int y, int z, int replaced, int replaceData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess item) {
|
||||
edits.add(new Edit(0, new Location(world, x, y, z), null, replaced, replaceData, replacedState, type, typeData, typeState, item));
|
||||
}
|
||||
|
||||
public long getElapsedTime() {
|
||||
@ -153,8 +153,8 @@ public class WorldEditor implements Runnable {
|
||||
}
|
||||
|
||||
private class Edit extends BlockChange {
|
||||
public Edit(long time, Location loc, Actor actor, int replaced, int replaceData, int type, int typeData, String signtext, ChestAccess ca) {
|
||||
super(time, loc, actor, replaced, replaceData, type, typeData, signtext, ca);
|
||||
public Edit(long time, Location loc, Actor actor, int replaced, int replaceData, byte[] replacedState, int type, int typeData, byte[] typeState, ChestAccess ca) {
|
||||
super(time, loc, actor, replaced, replaceData,replacedState , type, typeData, typeState, ca);
|
||||
}
|
||||
|
||||
PerformResult perform() throws WorldEditorException {
|
||||
@ -172,7 +172,7 @@ public class WorldEditor implements Runnable {
|
||||
if (BukkitUtils.isEmpty(replacedBlock.getMaterial()) && BukkitUtils.isEmpty(block.getType())) {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
final BlockState state = block.getState();
|
||||
BlockState state = block.getState();
|
||||
if (!world.isChunkLoaded(block.getChunk())) {
|
||||
world.loadChunk(block.getChunk());
|
||||
}
|
||||
@ -217,21 +217,18 @@ public class WorldEditor implements Runnable {
|
||||
}
|
||||
block.setBlockData(replacedBlock);
|
||||
BlockData newData = block.getBlockData();
|
||||
if (BlockStateCodecs.hasCodec(replacedBlock.getMaterial())) {
|
||||
state = block.getState();
|
||||
try {
|
||||
BlockStateCodecs.deserialize(state, replacedState);
|
||||
state.update();
|
||||
} catch (Exception e) {
|
||||
throw new WorldEditorException("Failed to restore blockstate of " + block.getType() + ": " + e, block.getLocation());
|
||||
}
|
||||
}
|
||||
|
||||
final Material curtype = block.getType();
|
||||
if (signtext != null && (curtype == Material.SIGN || curtype == Material.WALL_SIGN)) {
|
||||
final Sign sign = (Sign) block.getState();
|
||||
final String[] lines = signtext.split("\0", 4);
|
||||
if (lines.length < 4) {
|
||||
return PerformResult.NO_ACTION;
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
sign.setLine(i, lines[i]);
|
||||
}
|
||||
if (!sign.update()) {
|
||||
throw new WorldEditorException("Failed to update signtext of " + block.getType(), block.getLocation());
|
||||
}
|
||||
} else if (newData instanceof Bed) {
|
||||
if (newData instanceof Bed) {
|
||||
final Bed bed = (Bed) newData;
|
||||
final Block secBlock = bed.getPart() == Part.HEAD ? block.getRelative(bed.getFacing().getOppositeFace()) : block.getRelative(bed.getFacing());
|
||||
if (secBlock.isEmpty()) {
|
||||
|
@ -0,0 +1,15 @@
|
||||
package de.diddiz.LogBlock.blockstate;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public interface BlockStateCodec {
|
||||
Material[] getApplicableMaterials();
|
||||
|
||||
YamlConfiguration serialize(BlockState state);
|
||||
|
||||
void deserialize(BlockState state, YamlConfiguration conf);
|
||||
|
||||
String toString(YamlConfiguration conf);
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
package de.diddiz.LogBlock.blockstate;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.DyeColor;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.Banner;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.banner.Pattern;
|
||||
import org.bukkit.block.banner.PatternType;
|
||||
import org.bukkit.configuration.ConfigurationSection;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public class BlockStateCodecBanner implements BlockStateCodec {
|
||||
@Override
|
||||
public Material[] getApplicableMaterials() {
|
||||
return new Material[] { Material.WHITE_BANNER, Material.ORANGE_BANNER, Material.MAGENTA_BANNER, Material.LIGHT_BLUE_BANNER, Material.YELLOW_BANNER, Material.LIME_BANNER, Material.PINK_BANNER, Material.GRAY_BANNER, Material.LIGHT_GRAY_BANNER, Material.CYAN_BANNER, Material.PURPLE_BANNER,
|
||||
Material.BLUE_BANNER, Material.BROWN_BANNER, Material.GREEN_BANNER, Material.RED_BANNER, Material.BLACK_BANNER, Material.WHITE_WALL_BANNER, Material.ORANGE_WALL_BANNER, Material.MAGENTA_WALL_BANNER, Material.LIGHT_BLUE_WALL_BANNER, Material.YELLOW_WALL_BANNER,
|
||||
Material.LIME_WALL_BANNER, Material.PINK_WALL_BANNER, Material.GRAY_WALL_BANNER, Material.LIGHT_GRAY_WALL_BANNER, Material.CYAN_WALL_BANNER, Material.PURPLE_WALL_BANNER, Material.BLUE_WALL_BANNER, Material.BROWN_WALL_BANNER, Material.GREEN_WALL_BANNER, Material.RED_WALL_BANNER,
|
||||
Material.BLACK_WALL_BANNER };
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlConfiguration serialize(BlockState state) {
|
||||
if (state instanceof Banner) {
|
||||
Banner banner = (Banner) state;
|
||||
int nr = 0;
|
||||
List<Pattern> patterns = banner.getPatterns();
|
||||
if (!patterns.isEmpty()) {
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
ConfigurationSection patternsSection = conf.createSection("patterns");
|
||||
for (Pattern pattern : patterns) {
|
||||
ConfigurationSection section = patternsSection.createSection(Integer.toString(nr));
|
||||
section.set("color", pattern.getColor().name());
|
||||
section.set("pattern", pattern.getPattern().name());
|
||||
nr++;
|
||||
}
|
||||
return conf;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserialize(BlockState state, YamlConfiguration conf) {
|
||||
if (state instanceof Banner) {
|
||||
Banner banner = (Banner) state;
|
||||
int oldPatterns = banner.getPatterns().size();
|
||||
for (int i = 0; i < oldPatterns; i++) {
|
||||
banner.removePattern(0);
|
||||
}
|
||||
ConfigurationSection patternsSection = conf == null ? null : conf.getConfigurationSection("patterns");
|
||||
if (patternsSection != null) {
|
||||
for (String key : patternsSection.getKeys(false)) {
|
||||
ConfigurationSection section = patternsSection.getConfigurationSection(key);
|
||||
if (section != null) {
|
||||
DyeColor color = DyeColor.valueOf(section.getString("color"));
|
||||
PatternType type = PatternType.valueOf(section.getString("pattern"));
|
||||
banner.addPattern(new Pattern(color, type));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(YamlConfiguration conf) {
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package de.diddiz.LogBlock.blockstate;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public class BlockStateCodecSign implements BlockStateCodec {
|
||||
@Override
|
||||
public Material[] getApplicableMaterials() {
|
||||
return new Material[] { Material.WALL_SIGN, Material.SIGN };
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlConfiguration serialize(BlockState state) {
|
||||
if (state instanceof Sign) {
|
||||
Sign sign = (Sign) state;
|
||||
String[] lines = sign.getLines();
|
||||
boolean hasText = false;
|
||||
for (int i = 0; i < lines.length; i++) {
|
||||
if (lines[i] != null && lines[i].length() > 0) {
|
||||
hasText = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasText) {
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
conf.set("lines", Arrays.asList(lines));
|
||||
return conf;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is required for the SignChangeEvent, because we have no BlockState there.
|
||||
*/
|
||||
public static YamlConfiguration serialize(String[] lines) {
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
conf.set("lines", Arrays.asList(lines));
|
||||
return conf;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserialize(BlockState state, YamlConfiguration conf) {
|
||||
if (state instanceof Sign) {
|
||||
Sign sign = (Sign) state;
|
||||
List<String> lines = Collections.emptyList();
|
||||
if (conf != null) {
|
||||
lines = conf.getStringList("lines");
|
||||
}
|
||||
for (int i = 0; i < 4; i++) {
|
||||
String line = lines.size() > i && lines.get(i) != null ? lines.get(i) : "";
|
||||
sign.setLine(i, line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(YamlConfiguration conf) {
|
||||
if (conf != null) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String line : conf.getStringList("lines")) {
|
||||
if (sb.length() > 0)
|
||||
sb.append(" ");
|
||||
sb.append("[").append(line).append("]");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,54 @@
|
||||
package de.diddiz.LogBlock.blockstate;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.OfflinePlayer;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Skull;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
public class BlockStateCodecSkull implements BlockStateCodec {
|
||||
@Override
|
||||
public Material[] getApplicableMaterials() {
|
||||
return new Material[] { Material.PLAYER_WALL_HEAD, Material.PLAYER_HEAD };
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlConfiguration serialize(BlockState state) {
|
||||
if (state instanceof Skull) {
|
||||
Skull skull = (Skull) state;
|
||||
OfflinePlayer owner = skull.hasOwner() ? skull.getOwningPlayer() : null;
|
||||
if (owner != null) {
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
conf.set("owner", owner.getUniqueId().toString());
|
||||
return conf;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserialize(BlockState state, YamlConfiguration conf) {
|
||||
if (state instanceof Skull) {
|
||||
Skull skull = (Skull) state;
|
||||
UUID ownerId = conf == null ? null : UUID.fromString(conf.getString("owner"));
|
||||
if (ownerId == null) {
|
||||
skull.setOwningPlayer(null);
|
||||
} else {
|
||||
skull.setOwningPlayer(Bukkit.getOfflinePlayer(ownerId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(YamlConfiguration conf) {
|
||||
UUID ownerId = conf == null ? null : UUID.fromString(conf.getString("owner"));
|
||||
if (ownerId != null) {
|
||||
OfflinePlayer owner = Bukkit.getOfflinePlayer(ownerId);
|
||||
return "[" + (owner.getName() != null ? owner.getName() : owner.getUniqueId().toString()) + "]";
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
package de.diddiz.LogBlock.blockstate;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.CreatureSpawner;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.EntityType;
|
||||
|
||||
public class BlockStateCodecSpawner implements BlockStateCodec {
|
||||
@Override
|
||||
public Material[] getApplicableMaterials() {
|
||||
return new Material[] { Material.SPAWNER };
|
||||
}
|
||||
|
||||
@Override
|
||||
public YamlConfiguration serialize(BlockState state) {
|
||||
if (state instanceof CreatureSpawner) {
|
||||
CreatureSpawner spawner = (CreatureSpawner) state;
|
||||
YamlConfiguration conf = new YamlConfiguration();
|
||||
conf.set("delay", spawner.getDelay());
|
||||
conf.set("maxNearbyEntities", spawner.getMaxNearbyEntities());
|
||||
conf.set("maxSpawnDelay", spawner.getMaxSpawnDelay());
|
||||
conf.set("minSpawnDelay", spawner.getMinSpawnDelay());
|
||||
conf.set("requiredPlayerRange", spawner.getRequiredPlayerRange());
|
||||
conf.set("spawnCount", spawner.getSpawnCount());
|
||||
conf.set("spawnedType", spawner.getSpawnedType().name());
|
||||
conf.set("spawnRange", spawner.getSpawnRange());
|
||||
return conf;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deserialize(BlockState state, YamlConfiguration conf) {
|
||||
if (state instanceof CreatureSpawner) {
|
||||
CreatureSpawner spawner = (CreatureSpawner) state;
|
||||
if (conf != null) {
|
||||
spawner.setDelay(conf.getInt("delay"));
|
||||
spawner.setMaxNearbyEntities(conf.getInt("maxNearbyEntities"));
|
||||
spawner.setMaxSpawnDelay(conf.getInt("maxSpawnDelay"));
|
||||
spawner.setMinSpawnDelay(conf.getInt("minSpawnDelay"));
|
||||
spawner.setRequiredPlayerRange(conf.getInt("requiredPlayerRange"));
|
||||
spawner.setSpawnCount(conf.getInt("spawnCount"));
|
||||
spawner.setSpawnedType(EntityType.valueOf(conf.getString("spawnedType")));
|
||||
spawner.setSpawnRange(conf.getInt("spawnRange"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(YamlConfiguration conf) {
|
||||
if (conf != null) {
|
||||
EntityType entity = EntityType.valueOf(conf.getString("spawnedType"));
|
||||
if (entity != null) {
|
||||
return "[" + entity + "]";
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
package de.diddiz.LogBlock.blockstate;
|
||||
|
||||
import java.util.EnumMap;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.configuration.InvalidConfigurationException;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.util.Utils;
|
||||
|
||||
public class BlockStateCodecs {
|
||||
private static Map<Material, BlockStateCodec> codecs = new EnumMap<>(Material.class);
|
||||
|
||||
public static void registerCodec(BlockStateCodec codec) {
|
||||
Material[] materials = codec.getApplicableMaterials();
|
||||
for (Material material : materials) {
|
||||
if (codecs.containsKey(material)) {
|
||||
throw new IllegalArgumentException("BlockStateCodec for " + material + " already registered!");
|
||||
}
|
||||
codecs.put(material, codec);
|
||||
}
|
||||
}
|
||||
|
||||
static {
|
||||
registerCodec(new BlockStateCodecSign());
|
||||
registerCodec(new BlockStateCodecSkull());
|
||||
registerCodec(new BlockStateCodecBanner());
|
||||
registerCodec(new BlockStateCodecSpawner());
|
||||
}
|
||||
|
||||
public static boolean hasCodec(Material material) {
|
||||
return codecs.containsKey(material);
|
||||
}
|
||||
|
||||
public static byte[] serialize(BlockState state) {
|
||||
BlockStateCodec codec = codecs.get(state.getType());
|
||||
if (codec != null) {
|
||||
YamlConfiguration serialized = codec.serialize(state);
|
||||
if (serialized != null && !serialized.getKeys(false).isEmpty()) {
|
||||
return Utils.serializeYamlConfiguration(serialized);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void deserialize(BlockState block, byte[] state) {
|
||||
BlockStateCodec codec = codecs.get(block.getType());
|
||||
if (codec != null) {
|
||||
YamlConfiguration conf = null;
|
||||
try {
|
||||
if (state != null) {
|
||||
conf = Utils.deserializeYamlConfiguration(state);
|
||||
}
|
||||
} catch (InvalidConfigurationException e) {
|
||||
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Exception while deserializing BlockState", e);
|
||||
}
|
||||
codec.deserialize(block, conf);
|
||||
}
|
||||
}
|
||||
|
||||
public static String toString(Material material, byte[] state) {
|
||||
BlockStateCodec codec = codecs.get(material);
|
||||
if (codec != null) {
|
||||
YamlConfiguration conf = null;
|
||||
try {
|
||||
if (state != null) {
|
||||
conf = Utils.deserializeYamlConfiguration(state);
|
||||
}
|
||||
} catch (InvalidConfigurationException e) {
|
||||
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Exception while deserializing BlockState", e);
|
||||
}
|
||||
return codec.toString(conf);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ import com.sk89q.worldedit.world.block.BlockStateHolder;
|
||||
|
||||
import de.diddiz.LogBlock.LogBlock;
|
||||
import de.diddiz.LogBlock.Logging;
|
||||
import de.diddiz.LogBlock.blockstate.BlockStateCodecs;
|
||||
import de.diddiz.LogBlock.config.Config;
|
||||
import de.diddiz.util.BukkitUtils;
|
||||
|
||||
@ -22,8 +23,6 @@ import org.bukkit.Location;
|
||||
import org.bukkit.Material;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.block.BlockState;
|
||||
import org.bukkit.block.Sign;
|
||||
import org.bukkit.block.data.BlockData;
|
||||
|
||||
import java.util.logging.Level;
|
||||
@ -104,9 +103,8 @@ public class WorldEditLoggingHook {
|
||||
Material typeBefore = origin.getType();
|
||||
|
||||
// Check to see if we've broken a sign
|
||||
if (Config.isLogging(location.getWorld().getName(), Logging.SIGNTEXT) && (typeBefore == Material.SIGN || typeBefore == Material.WALL_SIGN)) {
|
||||
BlockState stateBefore = origin.getState();
|
||||
plugin.getConsumer().queueSignBreak(lbActor, (Sign) stateBefore);
|
||||
if (BlockStateCodecs.hasCodec(typeBefore)) {
|
||||
plugin.getConsumer().queueBlockBreak(lbActor, origin.getState());
|
||||
} else if (!origin.isEmpty()) {
|
||||
plugin.getConsumer().queueBlockBreak(lbActor, location, origin.getBlockData());
|
||||
}
|
||||
|
Reference in New Issue
Block a user