1 Commits

Author SHA1 Message Date
9003831622 First tries to get postgres up and running 2024-04-07 12:36:46 +02:00
35 changed files with 378 additions and 511 deletions

View File

@ -44,7 +44,7 @@
<dependency> <dependency>
<groupId>org.spigotmc</groupId> <groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId> <artifactId>spigot-api</artifactId>
<version>1.21.5-R0.1-SNAPSHOT</version> <version>1.20.4-R0.1-SNAPSHOT</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
@ -125,9 +125,9 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version> <version>3.12.1</version>
<configuration> <configuration>
<release>21</release> <release>17</release>
</configuration> </configuration>
</plugin> </plugin>
<plugin> <plugin>
@ -153,7 +153,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId> <artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version> <version>3.5.1</version>
<configuration> <configuration>
</configuration> </configuration>
<executions> <executions>

View File

@ -12,7 +12,6 @@ import static de.diddiz.LogBlock.util.TypeColor.DEFAULT;
import de.diddiz.LogBlock.blockstate.BlockStateCodecs; import de.diddiz.LogBlock.blockstate.BlockStateCodecs;
import de.diddiz.LogBlock.util.BukkitUtils; import de.diddiz.LogBlock.util.BukkitUtils;
import de.diddiz.LogBlock.util.ItemStackAndAmount;
import de.diddiz.LogBlock.util.Utils; import de.diddiz.LogBlock.util.Utils;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
@ -36,6 +35,7 @@ import org.bukkit.block.data.type.Repeater;
import org.bukkit.block.data.type.Sign; import org.bukkit.block.data.type.Sign;
import org.bukkit.block.data.type.Switch; import org.bukkit.block.data.type.Switch;
import org.bukkit.block.data.type.WallSign; import org.bukkit.block.data.type.WallSign;
import org.bukkit.inventory.ItemStack;
public class BlockChange implements LookupCacheElement { public class BlockChange implements LookupCacheElement {
public final long id, date; public final long id, date;
@ -75,7 +75,7 @@ public class BlockChange implements LookupCacheElement {
typeState = p.needType ? rs.getBytes("typeState") : null; typeState = p.needType ? rs.getBytes("typeState") : null;
ChestAccess catemp = null; ChestAccess catemp = null;
if (p.needChestAccess) { if (p.needChestAccess) {
ItemStackAndAmount stack = Utils.loadItemStack(rs.getBytes("item")); ItemStack stack = Utils.loadItemStack(rs.getBytes("item"));
if (stack != null) { if (stack != null) {
catemp = new ChestAccess(stack, rs.getBoolean("itemremove"), rs.getInt("itemtype")); catemp = new ChestAccess(stack, rs.getBoolean("itemremove"), rs.getInt("itemtype"));
} }
@ -113,7 +113,7 @@ public class BlockChange implements LookupCacheElement {
} }
@Override @Override
public BaseComponent getLogMessage(int entry) { public BaseComponent[] getLogMessage(int entry) {
TextComponent msg = new TextComponent(); TextComponent msg = new TextComponent();
if (date > 0) { if (date > 0) {
msg.addExtra(prettyDate(date)); msg.addExtra(prettyDate(date));
@ -127,7 +127,7 @@ public class BlockChange implements LookupCacheElement {
BlockData replaced = getBlockReplaced(); BlockData replaced = getBlockReplaced();
if (type == null || replaced == null) { if (type == null || replaced == null) {
msg.addExtra("did an unknown block modification"); msg.addExtra("did an unknown block modification");
return msg; return new BaseComponent[] { msg };
} }
// Process type details once for later use. // Process type details once for later use.
@ -254,7 +254,7 @@ public class BlockChange implements LookupCacheElement {
msg.addExtra(" at "); msg.addExtra(" at ");
msg.addExtra(prettyLocation(loc, entry)); msg.addExtra(prettyLocation(loc, entry));
} }
return msg; return new BaseComponent[] { msg };
} }
public BlockData getBlockReplaced() { public BlockData getBlockReplaced() {

View File

@ -39,7 +39,7 @@ public class ChatMessage implements LookupCacheElement {
} }
@Override @Override
public BaseComponent getLogMessage(int entry) { public BaseComponent[] getLogMessage(int entry) {
TextComponent msg = new TextComponent(); TextComponent msg = new TextComponent();
if (date > 0) { if (date > 0) {
msg.addExtra(prettyDate(date)); msg.addExtra(prettyDate(date));
@ -50,8 +50,10 @@ public class ChatMessage implements LookupCacheElement {
msg.addExtra(" "); msg.addExtra(" ");
} }
if (message != null) { if (message != null) {
msg.addExtra(TextComponent.fromLegacy(message)); for (BaseComponent messageComponent : TextComponent.fromLegacyText(message)) {
msg.addExtra(messageComponent);
}
} }
return msg; return new BaseComponent[] { msg };
} }
} }

View File

@ -1,13 +1,13 @@
package de.diddiz.LogBlock; package de.diddiz.LogBlock;
import de.diddiz.LogBlock.util.ItemStackAndAmount; import org.bukkit.inventory.ItemStack;
public class ChestAccess { public class ChestAccess {
public final ItemStackAndAmount itemStack; public final ItemStack itemStack;
public final boolean remove; public final boolean remove;
public final int itemType; public final int itemType;
public ChestAccess(ItemStackAndAmount itemStack, boolean remove, int itemType) { public ChestAccess(ItemStack itemStack, boolean remove, int itemType) {
this.itemStack = itemStack; this.itemStack = itemStack;
this.remove = remove; this.remove = remove;
this.itemType = itemType; this.itemType = itemType;

View File

@ -443,7 +443,9 @@ public class CommandsHandler implements CommandExecutor {
if (lookupElements[i].getLocation() != null) { if (lookupElements[i].getLocation() != null) {
message.addExtra(new TextComponent("(" + (i + 1) + ") ")); message.addExtra(new TextComponent("(" + (i + 1) + ") "));
} }
message.addExtra(lookupElements[i].getLogMessage(i + 1)); for (BaseComponent component : lookupElements[i].getLogMessage(i + 1)) {
message.addExtra(component);
}
sender.spigot().sendMessage(message); sender.spigot().sendMessage(message);
} }
if (setSessionPage) { if (setSessionPage) {

View File

@ -19,7 +19,6 @@ import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.util.ArrayDeque; import java.util.ArrayDeque;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Deque; import java.util.Deque;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
@ -53,7 +52,6 @@ import de.diddiz.LogBlock.config.Config;
import de.diddiz.LogBlock.events.BlockChangePreLogEvent; import de.diddiz.LogBlock.events.BlockChangePreLogEvent;
import de.diddiz.LogBlock.events.EntityChangePreLogEvent; import de.diddiz.LogBlock.events.EntityChangePreLogEvent;
import de.diddiz.LogBlock.util.BukkitUtils; import de.diddiz.LogBlock.util.BukkitUtils;
import de.diddiz.LogBlock.util.ItemStackAndAmount;
import de.diddiz.LogBlock.util.Utils; import de.diddiz.LogBlock.util.Utils;
public class Consumer extends Thread { public class Consumer extends Thread {
@ -210,7 +208,7 @@ public class Consumer extends Thread {
* @param remove * @param remove
* true if the item was removed * true if the item was removed
*/ */
public void queueChestAccess(Actor actor, BlockState container, ItemStackAndAmount itemStack, boolean remove) { public void queueChestAccess(Actor actor, BlockState container, ItemStack itemStack, boolean remove) {
if (!(container instanceof InventoryHolder)) { if (!(container instanceof InventoryHolder)) {
throw new IllegalArgumentException("Container must be instanceof InventoryHolder"); throw new IllegalArgumentException("Container must be instanceof InventoryHolder");
} }
@ -231,8 +229,8 @@ public class Consumer extends Thread {
* @param remove * @param remove
* true if the item was removed * true if the item was removed
*/ */
public void queueChestAccess(Actor actor, Location loc, BlockData type, ItemStackAndAmount itemStack, boolean remove) { public void queueChestAccess(Actor actor, Location loc, BlockData type, ItemStack itemStack, boolean remove) {
queueBlock(actor, loc, type, type, null, null, new ChestAccess(itemStack, remove, MaterialConverter.getOrAddMaterialId(itemStack.stack().getType()))); queueBlock(actor, loc, type, type, null, null, new ChestAccess(itemStack, remove, MaterialConverter.getOrAddMaterialId(itemStack.getType())));
} }
/** /**
@ -263,8 +261,8 @@ public class Consumer extends Thread {
* The inventory of the container block * The inventory of the container block
*/ */
public void queueContainerBreak(Actor actor, Location loc, BlockData type, Inventory inv) { public void queueContainerBreak(Actor actor, Location loc, BlockData type, Inventory inv) {
final Collection<ItemStackAndAmount> items = compressInventory(inv.getContents()); final ItemStack[] items = compressInventory(inv.getContents());
for (final ItemStackAndAmount item : items) { for (final ItemStack item : items) {
queueChestAccess(actor, loc, type, item, true); queueChestAccess(actor, loc, type, item, true);
} }
queueBlockBreak(actor, loc, type); queueBlockBreak(actor, loc, type);

View File

@ -77,7 +77,7 @@ public class EntityChange implements LookupCacheElement {
} }
@Override @Override
public BaseComponent getLogMessage(int entry) { public BaseComponent[] getLogMessage(int entry) {
TextComponent msg = new TextComponent(); TextComponent msg = new TextComponent();
if (date > 0) { if (date > 0) {
msg.addExtra(prettyDate(date)); msg.addExtra(prettyDate(date));
@ -128,7 +128,7 @@ public class EntityChange implements LookupCacheElement {
msg.addExtra(" at "); msg.addExtra(" at ");
msg.addExtra(prettyLocation(loc, entry)); msg.addExtra(prettyLocation(loc, entry));
} }
return msg; return new BaseComponent[] { msg };
} }
@Override @Override

View File

@ -49,7 +49,7 @@ public class Kill implements LookupCacheElement {
} }
@Override @Override
public BaseComponent getLogMessage(int entry) { public BaseComponent[] getLogMessage(int entry) {
TextComponent msg = new TextComponent(); TextComponent msg = new TextComponent();
if (date > 0) { if (date > 0) {
msg.addExtra(prettyDate(date)); msg.addExtra(prettyDate(date));
@ -65,7 +65,7 @@ public class Kill implements LookupCacheElement {
msg.addExtra(" with "); msg.addExtra(" with ");
msg.addExtra(prettyItemName(MaterialConverter.getMaterial(weapon))); msg.addExtra(prettyItemName(MaterialConverter.getMaterial(weapon)));
} }
return msg; return new BaseComponent[] { msg };
} }
public TextComponent prettyItemName(Material t) { public TextComponent prettyItemName(Material t) {

View File

@ -101,11 +101,19 @@ public class LogBlock extends JavaPlugin {
return; return;
} }
final Statement st = conn.createStatement(); final Statement st = conn.createStatement();
final ResultSet rs = st.executeQuery("SHOW CHARACTER SET where charset='utf8mb4';"); try {
if (rs.next()) { final ResultSet rs = st.executeQuery("SHOW CHARACTER SET where charset='utf8mb4';");
Config.mb4 = true; if (rs.next()) {
// Allegedly JDBC driver since 2010 hasn't needed this. I did. Config.mb4 = true;
st.executeUpdate("SET NAMES utf8mb4;"); // Allegedly JDBC driver since 2010 hasn't needed this. I did.
try {
st.executeUpdate("SET NAMES utf8mb4;");
} catch (Exception ex) {
getLogger().severe("could not set names to utf8mb4: " + ex.getMessage());
}
}
} catch (Exception ex) {
getLogger().severe("could not verify character set: " + ex.getMessage());
} }
conn.close(); conn.close();
Updater updater = new Updater(this); Updater updater = new Updater(this);
@ -205,8 +213,11 @@ public class LogBlock extends JavaPlugin {
if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) {
pm.registerEvents(new ChatLogging(this), this); pm.registerEvents(new ChatLogging(this), this);
} }
if (isLogging(Logging.WITHER) || isLogging(Logging.ENDERMEN)) { if (isLogging(Logging.ENDERMEN)) {
pm.registerEvents(new EntityChangeBlockLogging(this), this); pm.registerEvents(new EndermenLogging(this), this);
}
if (isLogging(Logging.WITHER)) {
pm.registerEvents(new WitherLogging(this), this);
} }
if (isLogging(Logging.NATURALSTRUCTUREGROW)) { if (isLogging(Logging.NATURALSTRUCTUREGROW)) {
pm.registerEvents(new StructureGrowLogging(this), this); pm.registerEvents(new StructureGrowLogging(this), this);

View File

@ -39,8 +39,6 @@ public enum Logging {
BAMBOOGROWTH, BAMBOOGROWTH,
WITHER(true), WITHER(true),
WITHER_SKULL(true), WITHER_SKULL(true),
GRASS_EAT,
MISCENTITYCHANGEBLOCK(true),
BONEMEALSTRUCTUREGROW, BONEMEALSTRUCTUREGROW,
WORLDEDIT, WORLDEDIT,
TNTMINECARTEXPLOSION(true), TNTMINECARTEXPLOSION(true),

View File

@ -6,11 +6,11 @@ import org.bukkit.Location;
public interface LookupCacheElement { public interface LookupCacheElement {
public Location getLocation(); public Location getLocation();
public default BaseComponent getLogMessage() { public default BaseComponent[] getLogMessage() {
return getLogMessage(-1); return getLogMessage(-1);
} }
public BaseComponent getLogMessage(int entry); public BaseComponent[] getLogMessage(int entry);
public default int getNumChanges() { public default int getNumChanges() {
return 1; return 1;

View File

@ -32,7 +32,7 @@ public class SummedBlockChanges implements LookupCacheElement {
} }
@Override @Override
public BaseComponent getLogMessage(int entry) { public BaseComponent[] getLogMessage(int entry) {
return MessagingUtil.formatSummarizedChanges(created, destroyed, actor != null ? new TextComponent(actor.getName()) : prettyMaterial(Objects.toString(MaterialConverter.getMaterial(type))), 10, 10, spaceFactor); return MessagingUtil.formatSummarizedChanges(created, destroyed, actor != null ? new TextComponent(actor.getName()) : prettyMaterial(Objects.toString(MaterialConverter.getMaterial(type))), 10, 10, spaceFactor);
} }

View File

@ -33,7 +33,7 @@ public class SummedEntityChanges implements LookupCacheElement {
} }
@Override @Override
public BaseComponent getLogMessage(int entry) { public BaseComponent[] getLogMessage(int entry) {
return MessagingUtil.formatSummarizedChanges(created, destroyed, actor != null ? new TextComponent(actor.getName()) : prettyMaterial(Objects.toString(EntityTypeConverter.getEntityType(type))), 10, 10, spaceFactor); return MessagingUtil.formatSummarizedChanges(created, destroyed, actor != null ? new TextComponent(actor.getName()) : prettyMaterial(Objects.toString(EntityTypeConverter.getEntityType(type))), 10, 10, spaceFactor);
} }

View File

@ -25,7 +25,7 @@ public class SummedKills implements LookupCacheElement {
} }
@Override @Override
public BaseComponent getLogMessage(int entry) { public BaseComponent[] getLogMessage(int entry) {
return MessagingUtil.formatSummarizedChanges(kills, killed, new TextComponent(player.getName()), 6, 7, spaceFactor); return MessagingUtil.formatSummarizedChanges(kills, killed, new TextComponent(player.getName()), 6, 7, spaceFactor);
} }

View File

@ -4,7 +4,6 @@ import de.diddiz.LogBlock.blockstate.BlockStateCodecSign;
import de.diddiz.LogBlock.config.Config; import de.diddiz.LogBlock.config.Config;
import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.LogBlock.config.WorldConfig;
import de.diddiz.LogBlock.util.ComparableVersion; import de.diddiz.LogBlock.util.ComparableVersion;
import de.diddiz.LogBlock.util.ItemStackAndAmount;
import de.diddiz.LogBlock.util.UUIDFetcher; import de.diddiz.LogBlock.util.UUIDFetcher;
import de.diddiz.LogBlock.util.Utils; import de.diddiz.LogBlock.util.Utils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
@ -535,7 +534,7 @@ class Updater {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
ItemStack stack = weaponMaterial.getMaxDurability() > 0 ? new ItemStack(weaponMaterial, Math.abs(amount), (short) itemdata) : new ItemStack(weaponMaterial, Math.abs(amount)); ItemStack stack = weaponMaterial.getMaxDurability() > 0 ? new ItemStack(weaponMaterial, Math.abs(amount), (short) itemdata) : new ItemStack(weaponMaterial, Math.abs(amount));
insertChestData.setLong(1, id); insertChestData.setLong(1, id);
insertChestData.setBytes(2, Utils.saveItemStack(ItemStackAndAmount.fromStack(stack))); insertChestData.setBytes(2, Utils.saveItemStack(stack));
insertChestData.setInt(3, amount >= 0 ? 0 : 1); insertChestData.setInt(3, amount >= 0 ? 0 : 1);
insertChestData.setInt(4, MaterialConverter.getOrAddMaterialId(weaponMaterial)); insertChestData.setInt(4, MaterialConverter.getOrAddMaterialId(weaponMaterial));
insertChestData.addBatch(); insertChestData.addBatch();
@ -870,49 +869,150 @@ class Updater {
} }
final Statement state = conn.createStatement(); final Statement state = conn.createStatement();
conn.setAutoCommit(true); conn.setAutoCommit(true);
createTable(state, "lb-players", "(playerid INT UNSIGNED NOT NULL AUTO_INCREMENT, UUID varchar(36) NOT NULL, 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), INDEX (UUID), INDEX (playername)) DEFAULT CHARSET " + charset); createTable(state, "lb-players",
"playerid INT UNSIGNED NOT NULL AUTO_INCREMENT, \n" +
"UUID varchar(36) NOT NULL, \n" +
"playername varchar(32) NOT NULL, \n" +
"firstlogin DATETIME NOT NULL, \n" +
"lastlogin DATETIME NOT NULL, \n" +
"onlinetime INT UNSIGNED NOT NULL, \n" +
"ip varchar(255) NOT NULL, \n" +
"PRIMARY KEY (playerid)\n",
//"INDEX (UUID), " +
//"INDEX (playername)",
"DEFAULT CHARSET " + charset
);
// Players table must not be empty or inserts won't work - bug #492 // Players table must not be empty or inserts won't work - bug #492
final ResultSet rs = state.executeQuery("SELECT NULL FROM `lb-players` LIMIT 1;"); final ResultSet rs = state.executeQuery("SELECT NULL FROM \"lb-players\" LIMIT 1;");
if (!rs.next()) { if (!rs.next()) {
state.execute("INSERT IGNORE INTO `lb-players` (UUID,playername) VALUES ('log_dummy_record','dummy_record')"); state.execute("INSERT INTO \"lb-players\" (UUID, playername) VALUES ('log_dummy_record','dummy_record') ON CONFLICT DO NOTHING");
} }
if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) { if (isLogging(Logging.CHAT) || isLogging(Logging.PLAYER_COMMANDS) || isLogging(Logging.CONSOLE_COMMANDS) || isLogging(Logging.COMMANDBLOCK_COMMANDS)) {
try { try {
createTable(state, "lb-chat", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, message VARCHAR(256) NOT NULL, PRIMARY KEY (id), KEY playerid (playerid), FULLTEXT message (message)) DEFAULT CHARSET " + charset); createTable(state, "lb-chat",
"id INT UNSIGNED NOT NULL AUTO_INCREMENT, " +
"date DATETIME NOT NULL, " +
"playerid INT UNSIGNED NOT NULL, " +
"message VARCHAR(256) NOT NULL, " +
"PRIMARY KEY (id), ",
// "KEY playerid (playerid), " +
// "FULLTEXT message (message)",
"DEFAULT CHARSET " + charset);
} catch (SQLException e) { } catch (SQLException e) {
createTable(state, "lb-chat", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, message VARCHAR(256) NOT NULL, PRIMARY KEY (id), KEY playerid (playerid)) DEFAULT CHARSET " + charset); createTable(state, "lb-chat",
"id INT UNSIGNED NOT NULL AUTO_INCREMENT," +
"date DATETIME NOT NULL," +
"playerid INT UNSIGNED NOT NULL," +
"message VARCHAR(256) NOT NULL," +
"PRIMARY KEY (id)," +
"KEY playerid (playerid)",
"DEFAULT CHARSET " + charset);
} }
} }
createTable(state, "lb-materials", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); createTable(state, "lb-materials",
createTable(state, "lb-blockstates", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); "id INT UNSIGNED NOT NULL, " +
createTable(state, "lb-entitytypes", "(id INT UNSIGNED NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY (id)) DEFAULT CHARSET " + charset); "name VARCHAR(255) NOT NULL, " +
"PRIMARY KEY (id)",
"DEFAULT CHARSET " + charset);
createTable(state, "lb-blockstates",
"id INT UNSIGNED NOT NULL, " +
"name VARCHAR(255) NOT NULL, " +
"PRIMARY KEY (id)",
"DEFAULT CHARSET " + charset);
createTable(state, "lb-entitytypes",
"id INT UNSIGNED NOT NULL, " +
"name VARCHAR(255) NOT NULL, " +
"PRIMARY KEY (id)",
"DEFAULT CHARSET " + charset);
for (final WorldConfig wcfg : getLoggedWorlds()) { for (final WorldConfig wcfg : getLoggedWorlds()) {
createTable(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 NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid))"); createTable(state, wcfg.table + "-blocks",
createTable(state, wcfg.table + "-chestdata", "(id INT UNSIGNED NOT NULL, item MEDIUMBLOB, itemremove TINYINT, itemtype SMALLINT NOT NULL DEFAULT '0', PRIMARY KEY (id))"); "id INT UNSIGNED NOT NULL AUTO_INCREMENT, " +
createTable(state, wcfg.table + "-state", "(id INT UNSIGNED NOT NULL, replacedState MEDIUMBLOB NULL, typeState MEDIUMBLOB NULL, PRIMARY KEY (id))"); "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 NOT NULL, " +
"z MEDIUMINT NOT NULL, " +
"PRIMARY KEY (id), " +
"KEY coords (x, z, y), " +
"KEY date (date), " +
"KEY playerid (playerid)",
"");
createTable(state, wcfg.table + "-chestdata",
"id INT UNSIGNED NOT NULL, " +
"item MEDIUMBLOB, " +
"itemremove TINYINT, " +
"itemtype SMALLINT NOT NULL DEFAULT '0', " +
"PRIMARY KEY (id)",
"");
createTable(state, wcfg.table + "-state",
"id INT UNSIGNED NOT NULL, " +
"replacedState MEDIUMBLOB NULL, " +
"typeState MEDIUMBLOB NULL, " +
"PRIMARY KEY (id)",
"");
if (wcfg.isLogging(Logging.KILL)) { if (wcfg.isLogging(Logging.KILL)) {
createTable(state, wcfg.table + "-kills", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, killer INT UNSIGNED, victim INT UNSIGNED NOT NULL, weapon SMALLINT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, PRIMARY KEY (id))"); createTable(state, wcfg.table + "-kills",
"id INT UNSIGNED NOT NULL AUTO_INCREMENT, " +
"date DATETIME NOT NULL, " +
"killer INT UNSIGNED, " +
"victim INT UNSIGNED NOT NULL, " +
"weapon SMALLINT UNSIGNED NOT NULL, " +
"x MEDIUMINT NOT NULL, " +
"y SMALLINT NOT NULL, " +
"z MEDIUMINT NOT NULL, " +
"PRIMARY KEY (id)",
"");
} }
createTable(state, wcfg.table + "-entityids", "(entityid INT UNSIGNED NOT NULL AUTO_INCREMENT, entityuuid VARCHAR(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, PRIMARY KEY (entityid), UNIQUE KEY (entityuuid))"); createTable(state, wcfg.table + "-entityids",
createTable(state, wcfg.table + "-entities", "(id INT UNSIGNED NOT NULL AUTO_INCREMENT, date DATETIME NOT NULL, playerid INT UNSIGNED NOT NULL, entityid INT UNSIGNED NOT NULL, entitytypeid INT UNSIGNED NOT NULL, x MEDIUMINT NOT NULL, y SMALLINT NOT NULL, z MEDIUMINT NOT NULL, action TINYINT UNSIGNED NOT NULL, data MEDIUMBLOB NULL, PRIMARY KEY (id), KEY coords (x, z, y), KEY date (date), KEY playerid (playerid), KEY entityid (entityid))"); "entityid INT UNSIGNED NOT NULL AUTO_INCREMENT, " +
"entityuuid VARCHAR(36) CHARACTER SET ascii COLLATE ascii_bin NOT NULL, " +
"PRIMARY KEY (entityid), " +
"UNIQUE KEY (entityuuid)",
"");
createTable(state, wcfg.table + "-entities",
"id INT UNSIGNED NOT NULL AUTO_INCREMENT, " +
"date DATETIME NOT NULL, " +
"playerid INT UNSIGNED NOT NULL, " +
"entityid INT UNSIGNED NOT NULL, " +
"entitytypeid INT UNSIGNED NOT NULL, " +
"x MEDIUMINT NOT NULL, " +
"y SMALLINT NOT NULL, " +
"z MEDIUMINT NOT NULL, " +
"action TINYINT UNSIGNED NOT NULL, " +
"data MEDIUMBLOB NULL, " +
"PRIMARY KEY (id), " +
"KEY coords (x, z, y), " +
"KEY date (date), " +
"KEY playerid (playerid), " +
"KEY entityid (entityid)",
"");
} }
state.close(); state.close();
conn.close(); conn.close();
} }
private void createTable(Statement state, String table, String query) throws SQLException { private void createTable(Statement state, String table, String columns, String additional) throws SQLException {
try (ResultSet tableResult = state.executeQuery("SHOW TABLES LIKE '" + table + "'")) { logblock.getLogger().log(Level.INFO, "Creating table " + table + ".");
if (!tableResult.next()) { String sql = "CREATE TABLE IF NOT EXISTS \"" + table + "\" (" +
logblock.getLogger().log(Level.INFO, "Creating table " + table + "."); (
state.execute("CREATE TABLE `" + table + "` " + query); columns
try (ResultSet tableResultNew = state.executeQuery("SHOW TABLES LIKE '" + table + "'")) { .replace("INT UNSIGNED NOT NULL AUTO_INCREMENT", "SERIAL NOT NULL")
if (!tableResultNew.next()) { .replace("INT UNSIGNED", "INT")
throw new SQLException("Table " + table + " not found and failed to create"); .replace("DATETIME", "TIMESTAMP")
} )
} + ") " /* + additional */ ;
} logblock.getLogger().info("sql=" + sql);
} state.execute(sql);
//try (ResultSet tableResultNew = state.executeQuery("SHOW TABLES LIKE '" + table + "'")) {
// if (!tableResultNew.next()) {
// throw new SQLException("Table " + table + " not found and failed to create");
// }
//}
} }
/** /**

View File

@ -24,7 +24,6 @@ import org.bukkit.entity.Bee;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.ItemFrame; import org.bukkit.entity.ItemFrame;
import org.bukkit.inventory.EquipmentSlot; import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import de.diddiz.LogBlock.QueryParams.Order; import de.diddiz.LogBlock.QueryParams.Order;
@ -36,7 +35,6 @@ import java.io.File;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.text.NumberFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@ -55,8 +53,6 @@ import static de.diddiz.LogBlock.util.BukkitUtils.*;
public class WorldEditor implements Runnable { public class WorldEditor implements Runnable {
private final LogBlock logblock; private final LogBlock logblock;
private final ArrayList<Edit> edits = new ArrayList<>(); private final ArrayList<Edit> edits = new ArrayList<>();
private int rowsCompleted;
private int totalRows;
private final World world; private final World world;
/** /**
@ -139,7 +135,6 @@ public class WorldEditor implements Runnable {
} }
started = true; started = true;
final long start = System.currentTimeMillis(); final long start = System.currentTimeMillis();
totalRows = edits.size();
taskID = logblock.getServer().getScheduler().scheduleSyncRepeatingTask(logblock, this, 0, 1); taskID = logblock.getServer().getScheduler().scheduleSyncRepeatingTask(logblock, this, 0, 1);
if (taskID == -1) { if (taskID == -1) {
throw new Exception("Failed to schedule task"); throw new Exception("Failed to schedule task");
@ -156,9 +151,8 @@ public class WorldEditor implements Runnable {
public synchronized void run() { public synchronized void run() {
final List<WorldEditorException> errorList = new ArrayList<>(); final List<WorldEditorException> errorList = new ArrayList<>();
int counter = 0; int counter = 0;
long t0 = System.nanoTime(); float size = edits.size();
long maxEditTime = 5_000_000; // 5 ms while (!edits.isEmpty() && counter < 100) {
while (!edits.isEmpty() && counter < 10000 && (counter < 100 || counter % 10 != 0 || System.nanoTime() - t0 < maxEditTime)) {
try { try {
switch (edits.remove(edits.size() - 1).perform()) { switch (edits.remove(edits.size() - 1).perform()) {
case SUCCESS: case SUCCESS:
@ -175,12 +169,11 @@ public class WorldEditor implements Runnable {
} catch (final Exception ex) { } catch (final Exception ex) {
logblock.getLogger().log(Level.WARNING, "[WorldEditor] Exeption: ", ex); logblock.getLogger().log(Level.WARNING, "[WorldEditor] Exeption: ", ex);
} }
rowsCompleted++;
counter++; counter++;
if (sender != null) { if (sender != null) {
float percentage = rowsCompleted * 100.0f / totalRows; float percentage = ((size - edits.size()) / size) * 100.0F;
if (rowsCompleted % 10000 == 0) { if (percentage % 20 == 0) {
sender.sendMessage(ChatColor.GOLD + "[LogBlock]" + ChatColor.YELLOW + " Rollback progress: " + NumberFormat.getNumberInstance().format(percentage) + "%" + sender.sendMessage(ChatColor.GOLD + "[LogBlock]" + ChatColor.YELLOW + " Rollback progress: " + percentage + "%" +
" Blocks edited: " + counter); " Blocks edited: " + counter);
} }
} }
@ -375,10 +368,10 @@ public class WorldEditor implements Runnable {
BlockState state = block.getState(); BlockState state = block.getState();
if (setBlock.equals(replacedBlock)) { if (setBlock.equals(replacedBlock)) {
if (ca != null) { if (ca != null) {
if (state instanceof InventoryHolder && state.getType() == replacedBlock.getMaterial()) { if (state instanceof Container && state.getType() == replacedBlock.getMaterial()) {
int leftover; int leftover;
try { try {
leftover = modifyContainer(state, ca.itemStack, !ca.remove); leftover = modifyContainer(state, new ItemStack(ca.itemStack), !ca.remove);
} catch (final Exception ex) { } catch (final Exception ex) {
throw new WorldEditorException(ex.getMessage(), block.getLocation()); throw new WorldEditorException(ex.getMessage(), block.getLocation());
} }
@ -493,8 +486,8 @@ public class WorldEditor implements Runnable {
} }
@Override @Override
public BaseComponent getLogMessage(int entry) { public BaseComponent[] getLogMessage(int entry) {
return TextComponent.fromLegacy(getMessage()); return TextComponent.fromLegacyText(getMessage());
} }
} }
} }

View File

@ -3,8 +3,9 @@ package de.diddiz.LogBlock;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import org.bukkit.inventory.ItemStack;
import de.diddiz.LogBlock.QueryParams.BlockChangeType; import de.diddiz.LogBlock.QueryParams.BlockChangeType;
import de.diddiz.LogBlock.util.ItemStackAndAmount;
import de.diddiz.LogBlock.util.Utils; import de.diddiz.LogBlock.util.Utils;
public class WorldEditorEditFactory { public class WorldEditorEditFactory {
@ -24,7 +25,7 @@ public class WorldEditorEditFactory {
return; return;
} }
ChestAccess chestaccess = null; ChestAccess chestaccess = null;
ItemStackAndAmount stack = Utils.loadItemStack(rs.getBytes("item")); ItemStack stack = Utils.loadItemStack(rs.getBytes("item"));
if (stack != null) { if (stack != null) {
chestaccess = new ChestAccess(stack, rs.getBoolean("itemremove") == rollback, rs.getInt("itemtype")); chestaccess = new ChestAccess(stack, rs.getBoolean("itemremove") == rollback, rs.getInt("itemtype"));
} }

View File

@ -1,12 +1,9 @@
package de.diddiz.LogBlock.blockstate; package de.diddiz.LogBlock.blockstate;
import java.util.List; import java.util.List;
import java.util.Locale;
import net.md_5.bungee.api.chat.BaseComponent; import net.md_5.bungee.api.chat.BaseComponent;
import org.bukkit.DyeColor; import org.bukkit.DyeColor;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.Registry;
import org.bukkit.block.Banner; import org.bukkit.block.Banner;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.block.banner.Pattern; import org.bukkit.block.banner.Pattern;
@ -33,13 +30,10 @@ public class BlockStateCodecBanner implements BlockStateCodec {
YamlConfiguration conf = new YamlConfiguration(); YamlConfiguration conf = new YamlConfiguration();
ConfigurationSection patternsSection = conf.createSection("patterns"); ConfigurationSection patternsSection = conf.createSection("patterns");
for (Pattern pattern : patterns) { for (Pattern pattern : patterns) {
NamespacedKey key = pattern.getPattern().getKey(); ConfigurationSection section = patternsSection.createSection(Integer.toString(nr));
if (key != null) { section.set("color", pattern.getColor().name());
ConfigurationSection section = patternsSection.createSection(Integer.toString(nr)); section.set("pattern", pattern.getPattern().name());
section.set("color", pattern.getColor().name()); nr++;
section.set("pattern", key.toString());
nr++;
}
} }
return conf; return conf;
} }
@ -61,13 +55,8 @@ public class BlockStateCodecBanner implements BlockStateCodec {
ConfigurationSection section = patternsSection.getConfigurationSection(key); ConfigurationSection section = patternsSection.getConfigurationSection(key);
if (section != null) { if (section != null) {
DyeColor color = DyeColor.valueOf(section.getString("color")); DyeColor color = DyeColor.valueOf(section.getString("color"));
NamespacedKey patternKey = NamespacedKey.fromString(section.getString("pattern").toLowerCase(Locale.ROOT)); PatternType type = PatternType.valueOf(section.getString("pattern"));
if (patternKey != null) { banner.addPattern(new Pattern(color, type));
PatternType type = Registry.BANNER_PATTERN.get(patternKey);
if (type != null) {
banner.addPattern(new Pattern(color, type));
}
}
} }
} }
} }

View File

@ -182,7 +182,7 @@ public class BlockStateCodecSign implements BlockStateCodec {
} }
tc.addExtra("["); tc.addExtra("[");
if (line != null && !line.isEmpty()) { if (line != null && !line.isEmpty()) {
tc.addExtra(TextComponent.fromLegacy(line)); tc.addExtra(new TextComponent(TextComponent.fromLegacyText(line)));
} }
tc.addExtra("]"); tc.addExtra("]");
} }

View File

@ -7,8 +7,8 @@ import java.util.List;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
public enum EntityLogging { public enum EntityLogging {
SPAWN(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.SNOW_GOLEM.name() }), SPAWN(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.SNOWMAN.name() }),
DESTROY(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.VILLAGER.name(), EntityType.SNOW_GOLEM.name(), "ANIMAL" }), DESTROY(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.VILLAGER.name(), EntityType.SNOWMAN.name(), "ANIMAL" }),
MODIFY(new String[] { "ALL" }); MODIFY(new String[] { "ALL" });
public static final int length = EntityLogging.values().length; public static final int length = EntityLogging.values().length;

View File

@ -2,7 +2,6 @@ package de.diddiz.LogBlock.listeners;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.BlockFace; import org.bukkit.block.BlockFace;
import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.ArmorStand; import org.bukkit.entity.ArmorStand;
@ -193,17 +192,18 @@ public class AdvancedEntityLogging extends LoggingListener {
LivingEntity entity = event.getEntity(); LivingEntity entity = event.getEntity();
if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) { if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) {
Actor actor = null; Actor actor = null;
Entity cause = event.getDamageSource().getCausingEntity(); EntityDamageEvent lastDamage = entity.getLastDamageCause();
Entity damager = LoggingUtil.getRealDamager(cause); if (lastDamage instanceof EntityDamageByEntityEvent) {
if (damager != null) { Entity damager = LoggingUtil.getRealDamager(((EntityDamageByEntityEvent) lastDamage).getDamager());
actor = Actor.actorFromEntity(damager); if (damager != null) {
actor = Actor.actorFromEntity(damager);
}
} }
if (actor == null && entity.getKiller() != null) { if (actor == null && entity.getKiller() != null) {
actor = Actor.actorFromEntity(entity.getKiller()); actor = Actor.actorFromEntity(entity.getKiller());
} }
if (actor == null) { if (actor == null) {
NamespacedKey key = event.getDamageSource().getDamageType().getKey(); actor = new Actor(lastDamage == null ? "UNKNOWN" : lastDamage.getCause().toString());
actor = new Actor(key == null ? "unknown" : key.getKey().toUpperCase());
} }
queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL); queueEntitySpawnOrKill(entity, actor, EntityChange.EntityChangeType.KILL);
} }

View File

@ -3,31 +3,21 @@ package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.util.ItemStackAndAmount;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState; import org.bukkit.block.BlockState;
import org.bukkit.block.DecoratedPot;
import org.bukkit.block.DoubleChest; import org.bukkit.block.DoubleChest;
import org.bukkit.block.data.type.ChiseledBookshelf;
import org.bukkit.entity.HumanEntity; import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.inventory.ClickType; import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent; import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent; import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent; import org.bukkit.event.inventory.InventoryDragEvent;
import org.bukkit.event.inventory.InventoryOpenEvent; import org.bukkit.event.inventory.InventoryOpenEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.Inventory; import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -79,10 +69,9 @@ public class ChestAccessLogging extends LoggingListener {
for (Entry<ItemStack, Integer> e : modifications.entrySet()) { for (Entry<ItemStack, Integer> e : modifications.entrySet()) {
ItemStack stack = e.getKey(); ItemStack stack = e.getKey();
int amount = e.getValue(); int amount = e.getValue();
if (amount != 0) { stack.setAmount(Math.abs(amount));
// consumer.getLogblock().getLogger().info("Store container: " + stack + " take: " + (amount < 0)); // consumer.getLogblock().getLogger().info("Store container: " + stack + " take: " + (amount < 0));
consumer.queueChestAccess(Actor.actorFromEntity(actor), location, location.getWorld().getBlockAt(location).getBlockData(), new ItemStackAndAmount(stack, Math.abs(amount)), amount < 0); consumer.queueChestAccess(Actor.actorFromEntity(actor), location, location.getWorld().getBlockAt(location).getBlockData(), stack, amount < 0);
}
} }
modifications.clear(); modifications.clear();
} }
@ -311,62 +300,4 @@ public class ChestAccessLogging extends LoggingListener {
} }
} }
} }
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent event) {
final Block clicked = event.getClickedBlock();
if (event.getAction() != Action.RIGHT_CLICK_BLOCK || event.getHand() != EquipmentSlot.HAND || !event.hasBlock() || clicked == null) {
return;
}
final Player player = event.getPlayer();
if (!isLogging(player.getWorld(), Logging.CHESTACCESS)) {
return;
}
final Material type = clicked.getType();
if (type == Material.DECORATED_POT) {
ItemStack mainHand = player.getInventory().getItemInMainHand();
if (mainHand != null && mainHand.getType() != Material.AIR && clicked.getState() instanceof DecoratedPot pot) {
ItemStack currentInPot = pot.getSnapshotInventory().getItem();
if (currentInPot == null || currentInPot.getType() == Material.AIR || currentInPot.isSimilar(mainHand) && currentInPot.getAmount() < currentInPot.getMaxStackSize()) {
ItemStack stack = mainHand.clone();
stack.setAmount(1);
consumer.queueChestAccess(Actor.actorFromEntity(player), clicked.getLocation(), clicked.getBlockData(), ItemStackAndAmount.fromStack(stack), false);
}
}
} else if (type == Material.CHISELED_BOOKSHELF) {
if (clicked.getBlockData() instanceof ChiseledBookshelf blockData && blockData.getFacing() == event.getBlockFace() && clicked.getState() instanceof org.bukkit.block.ChiseledBookshelf bookshelf) {
// calculate the slot the same way as minecraft does it
Vector pos = event.getClickedPosition();
if (pos == null) {
return; // some plugins create this event without a clicked pos
}
double clickx = switch (blockData.getFacing()) {
case NORTH -> 1 - pos.getX();
case SOUTH -> pos.getX();
case EAST -> 1 - pos.getZ();
case WEST -> pos.getZ();
default -> throw new IllegalArgumentException("Unexpected facing for chiseled bookshelf: " + blockData.getFacing());
};
int col = clickx < 0.375 ? 0 : (clickx < 0.6875 ? 1 : 2); // 6/16 ; 11/16
int row = pos.getY() >= 0.5 ? 0 : 1;
int slot = col + row * 3;
ItemStack currentInSlot = bookshelf.getSnapshotInventory().getItem(slot);
if (blockData.isSlotOccupied(slot)) {
// not empty: always take
if (currentInSlot != null && currentInSlot.getType() != Material.AIR) {
consumer.queueChestAccess(Actor.actorFromEntity(player), clicked.getLocation(), clicked.getBlockData(), ItemStackAndAmount.fromStack(currentInSlot), true);
}
} else {
// empty: put if has tag BOOKSHELF_BOOKS
ItemStack mainHand = player.getInventory().getItemInMainHand();
if (mainHand != null && mainHand.getType() != Material.AIR && Tag.ITEMS_BOOKSHELF_BOOKS.isTagged(mainHand.getType())) {
ItemStack stack = mainHand.clone();
stack.setAmount(1);
consumer.queueChestAccess(Actor.actorFromEntity(player), clicked.getLocation(), clicked.getBlockData(), ItemStackAndAmount.fromStack(stack), false);
}
}
}
}
}
} }

View File

@ -0,0 +1,24 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.entity.Enderman;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class EndermenLogging extends LoggingListener {
public EndermenLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
if (event.getEntity() instanceof Enderman && isLogging(event.getBlock().getWorld(), Logging.ENDERMEN)) {
consumer.queueBlockReplace(new Actor("Enderman"), event.getBlock().getState(), event.getBlockData()); // Figure out how to get the data of the placed block;
}
}
}

View File

@ -1,46 +0,0 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.Material;
import org.bukkit.entity.Enderman;
import org.bukkit.entity.Player;
import org.bukkit.entity.Sheep;
import org.bukkit.entity.Wither;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class EntityChangeBlockLogging extends LoggingListener {
public EntityChangeBlockLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
Material oldType = event.getBlock().getType();
if ((oldType == Material.REDSTONE_ORE || oldType == Material.DEEPSLATE_REDSTONE_ORE) && event.getBlockData().getMaterial() == oldType) {
return; // ignore redstone ore activation by stepping on it
}
if (event.getEntity() instanceof Wither) {
if (isLogging(event.getBlock().getWorld(), Logging.WITHER)) {
consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), event.getBlock().getState(), event.getBlockData());
}
} else if (event.getEntity() instanceof Enderman) {
if (isLogging(event.getBlock().getWorld(), Logging.ENDERMEN)) {
consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), event.getBlock().getState(), event.getBlockData());
}
} else if (event.getEntity() instanceof Sheep) {
if (isLogging(event.getBlock().getWorld(), Logging.GRASS_EAT)) {
consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), event.getBlock().getState(), event.getBlockData());
}
} else {
if (isLogging(event.getBlock().getWorld(), event.getEntity() instanceof Player ? Logging.BLOCKPLACE : Logging.MISCENTITYCHANGEBLOCK)) {
consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), event.getBlock().getState(), event.getBlockData());
}
}
}
}

View File

@ -7,7 +7,6 @@ import de.diddiz.LogBlock.config.Config;
import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.LogBlock.config.WorldConfig;
import de.diddiz.LogBlock.util.BukkitUtils; import de.diddiz.LogBlock.util.BukkitUtils;
import org.bukkit.Bukkit; import org.bukkit.Bukkit;
import org.bukkit.ExplosionResult;
import org.bukkit.Location; import org.bukkit.Location;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.block.Block; import org.bukkit.block.Block;
@ -42,9 +41,6 @@ public class ExplosionLogging extends LoggingListener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityExplode(EntityExplodeEvent event) { public void onEntityExplode(EntityExplodeEvent event) {
if (event.getExplosionResult() == ExplosionResult.KEEP || event.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK) {
return;
}
final WorldConfig wcfg = getWorldConfig(event.getLocation().getWorld()); final WorldConfig wcfg = getWorldConfig(event.getLocation().getWorld());
if (wcfg != null) { if (wcfg != null) {
Actor actor = new Actor("Explosion"); Actor actor = new Actor("Explosion");
@ -178,9 +174,6 @@ public class ExplosionLogging extends LoggingListener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockExplode(BlockExplodeEvent event) { public void onBlockExplode(BlockExplodeEvent event) {
if (event.getExplosionResult() == ExplosionResult.KEEP || event.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK) {
return;
}
Player bedCause = null; Player bedCause = null;
if (lastBedInteractionPlayer != null && lastBedInteractionLocation != null) { if (lastBedInteractionPlayer != null && lastBedInteractionLocation != null) {
Location block = event.getBlock().getLocation(); Location block = event.getBlock().getLocation();

View File

@ -4,13 +4,14 @@ import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.Config.*; import de.diddiz.LogBlock.config.Config.*;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Entity; import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity; import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Monster; import org.bukkit.entity.Monster;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent; import org.bukkit.event.entity.EntityDeathEvent;
import static de.diddiz.LogBlock.config.Config.*; import static de.diddiz.LogBlock.config.Config.*;
@ -23,26 +24,27 @@ public class KillLogging extends LoggingListener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityDeath(EntityDeathEvent deathEvent) { public void onEntityDeath(EntityDeathEvent deathEvent) {
if (isLogging(deathEvent.getEntity().getWorld(), Logging.KILL)) { EntityDamageEvent event = deathEvent.getEntity().getLastDamageCause();
LivingEntity victim = deathEvent.getEntity(); // For a death event, there should always be a damage event and it should not be cancelled. Check anyway.
Entity killer = deathEvent.getDamageSource().getCausingEntity(); if (event != null && event.isCancelled() == false && isLogging(event.getEntity().getWorld(), Logging.KILL) && event.getEntity() instanceof LivingEntity) {
if (killer != null) { final LivingEntity victim = (LivingEntity) event.getEntity();
if (event instanceof EntityDamageByEntityEvent) {
final Entity killer = ((EntityDamageByEntityEvent) event).getDamager();
if (logKillsLevel == LogKillsLevel.PLAYERS && !(victim instanceof Player && killer instanceof Player)) { if (logKillsLevel == LogKillsLevel.PLAYERS && !(victim instanceof Player && killer instanceof Player)) {
return; return;
} else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster) && killer instanceof Player || killer instanceof Monster)) { } else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster) && killer instanceof Player || killer instanceof Monster)) {
return; return;
} }
consumer.queueKill(killer, victim); consumer.queueKill(killer, victim);
} else if (deathEvent.getEntity().getKiller() != null) {
consumer.queueKill(deathEvent.getEntity().getKiller(), victim);
} else if (logEnvironmentalKills) { } else if (logEnvironmentalKills) {
if (logKillsLevel == LogKillsLevel.PLAYERS && !(victim instanceof Player)) { if (logKillsLevel == LogKillsLevel.PLAYERS && !(victim instanceof Player)) {
return; return;
} else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster))) { } else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster))) {
return; return;
} }
NamespacedKey key = deathEvent.getDamageSource().getDamageType().getKey(); consumer.queueKill(new Actor(event.getCause().toString()), victim);
Actor actor = new Actor(key == null ? "unknown" : key.getKey().toUpperCase());
consumer.queueKill(actor, victim);
} }
} }
} }

View File

@ -1,24 +1,18 @@
package de.diddiz.LogBlock.listeners; package de.diddiz.LogBlock.listeners;
import static de.diddiz.LogBlock.config.Config.getWorldConfig; import static de.diddiz.LogBlock.config.Config.getWorldConfig;
import static de.diddiz.LogBlock.config.Config.isLogging;
import de.diddiz.LogBlock.Actor; import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging; import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig; import de.diddiz.LogBlock.config.WorldConfig;
import org.bukkit.Bukkit;
import org.bukkit.Material; import org.bukkit.Material;
import org.bukkit.Tag; import org.bukkit.block.BlockState;
import org.bukkit.block.Block;
import org.bukkit.block.Lectern; import org.bukkit.block.Lectern;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler; import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority; import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action; import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.player.PlayerTakeLecternBookEvent; import org.bukkit.event.player.PlayerTakeLecternBookEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack; import org.bukkit.inventory.ItemStack;
public class LecternLogging extends LoggingListener { public class LecternLogging extends LoggingListener {
@ -27,31 +21,25 @@ public class LecternLogging extends LoggingListener {
} }
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true) @EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onPlayerInteract(PlayerInteractEvent event) { public void onBlockPlace(BlockPlaceEvent event) {
final Block clicked = event.getClickedBlock(); final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld());
if (event.getAction() != Action.RIGHT_CLICK_BLOCK || event.getHand() != EquipmentSlot.HAND || !event.hasBlock() || clicked == null) { if (wcfg != null && wcfg.isLogging(Logging.LECTERNBOOKCHANGE)) {
return; final BlockState before = event.getBlockReplacedState();
} final BlockState after = event.getBlockPlaced().getState();
final Player player = event.getPlayer(); if (before.getType() == Material.LECTERN && after.getType() == Material.LECTERN) {
if (!isLogging(player.getWorld(), Logging.LECTERNBOOKCHANGE)) { Lectern lecternBefore = (Lectern) before.getBlock().getState();
return; ItemStack book = lecternBefore.getSnapshotInventory().getItem(0);
} try {
final Material type = clicked.getType(); lecternBefore.getSnapshotInventory().setItem(0, null);
if (type == Material.LECTERN) { } catch (NullPointerException e) {
ItemStack mainHand = player.getInventory().getItemInMainHand(); //ignored
if (mainHand != null && mainHand.getType() != Material.AIR && Tag.ITEMS_LECTERN_BOOKS.isTagged(mainHand.getType()) && clicked.getState() instanceof Lectern lectern) { }
ItemStack currentInLectern = lectern.getSnapshotInventory().getItem(0); lecternBefore.setBlockData(before.getBlockData());
if (currentInLectern == null || currentInLectern.getType() == Material.AIR) { consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), lecternBefore, after);
ItemStack stack = mainHand.clone(); try {
stack.setAmount(1); lecternBefore.getSnapshotInventory().setItem(0, book);
Lectern newLectern = (Lectern) clicked.getState(); } catch (NullPointerException e) {
newLectern.getSnapshotInventory().setItem(0, stack); //ignored
org.bukkit.block.data.type.Lectern blockDataOld = (org.bukkit.block.data.type.Lectern) newLectern.getBlockData();
org.bukkit.block.data.type.Lectern blockDataWithBook = (org.bukkit.block.data.type.Lectern) Bukkit.createBlockData("lectern[has_book=true]");
blockDataWithBook.setFacing(blockDataOld.getFacing());
blockDataWithBook.setPowered(blockDataOld.isPowered());
newLectern.setBlockData(blockDataWithBook);
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), lectern, newLectern);
} }
} }
} }

View File

@ -0,0 +1,24 @@
package de.diddiz.LogBlock.listeners;
import de.diddiz.LogBlock.Actor;
import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.Logging;
import org.bukkit.entity.Wither;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityChangeBlockEvent;
import static de.diddiz.LogBlock.config.Config.isLogging;
public class WitherLogging extends LoggingListener {
public WitherLogging(LogBlock lb) {
super(lb);
}
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityChangeBlock(EntityChangeBlockEvent event) {
if (event.getEntity() instanceof Wither && isLogging(event.getBlock().getWorld(), Logging.WITHER)) {
consumer.queueBlockReplace(Actor.actorFromEntity(event.getEntity()), event.getBlock().getState(), event.getBlockData()); // Wither walked through a block.
}
}
}

View File

@ -4,14 +4,13 @@ import static de.diddiz.LogBlock.util.MessagingUtil.prettyMaterial;
import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.LogBlock;
import java.io.File; import java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
@ -148,11 +147,8 @@ public class BukkitUtils {
// https://minecraft.fandom.com/wiki/Tag#blocks_small_flowers // https://minecraft.fandom.com/wiki/Tag#blocks_small_flowers
Set<Material> smallFlowers = Tag.SMALL_FLOWERS.getValues(); Set<Material> smallFlowers = Tag.SMALL_FLOWERS.getValues();
Set<Material> tallFlowers = Set.of(Material.SUNFLOWER, // https://minecraft.fandom.com/wiki/Tag#blocks_tall_flowers
Material.LILAC, Set<Material> tallFlowers = Tag.TALL_FLOWERS.getValues();
Material.PEONY,
Material.ROSE_BUSH,
Material.PITCHER_PLANT);
Set<Material> bannerStanding = Set.of(Material.WHITE_BANNER, Set<Material> bannerStanding = Set.of(Material.WHITE_BANNER,
Material.ORANGE_BANNER, Material.ORANGE_BANNER,
@ -335,7 +331,6 @@ public class BukkitUtils {
containerBlocks.add(Material.BLAST_FURNACE); containerBlocks.add(Material.BLAST_FURNACE);
containerBlocks.add(Material.SMOKER); containerBlocks.add(Material.SMOKER);
containerBlocks.add(Material.CHISELED_BOOKSHELF); containerBlocks.add(Material.CHISELED_BOOKSHELF);
containerBlocks.add(Material.DECORATED_POT);
// Doesn't actually have a block inventory // Doesn't actually have a block inventory
// containerBlocks.add(Material.ENDER_CHEST); // containerBlocks.add(Material.ENDER_CHEST);
@ -346,13 +341,12 @@ public class BukkitUtils {
projectileItems.put(EntityType.ENDER_PEARL, Material.ENDER_PEARL); projectileItems.put(EntityType.ENDER_PEARL, Material.ENDER_PEARL);
projectileItems.put(EntityType.SMALL_FIREBALL, Material.FIRE_CHARGE); // Fire charge projectileItems.put(EntityType.SMALL_FIREBALL, Material.FIRE_CHARGE); // Fire charge
projectileItems.put(EntityType.FIREBALL, Material.FIRE_CHARGE); // Fire charge projectileItems.put(EntityType.FIREBALL, Material.FIRE_CHARGE); // Fire charge
projectileItems.put(EntityType.FISHING_BOBBER, Material.FISHING_ROD); projectileItems.put(EntityType.FISHING_HOOK, Material.FISHING_ROD);
projectileItems.put(EntityType.SNOWBALL, Material.SNOWBALL); projectileItems.put(EntityType.SNOWBALL, Material.SNOWBALL);
projectileItems.put(EntityType.SPLASH_POTION, Material.SPLASH_POTION); projectileItems.put(EntityType.SPLASH_POTION, Material.SPLASH_POTION);
projectileItems.put(EntityType.LINGERING_POTION, Material.LINGERING_POTION); projectileItems.put(EntityType.THROWN_EXP_BOTTLE, Material.EXPERIENCE_BOTTLE);
projectileItems.put(EntityType.EXPERIENCE_BOTTLE, Material.EXPERIENCE_BOTTLE);
projectileItems.put(EntityType.WITHER_SKULL, Material.WITHER_SKELETON_SKULL); projectileItems.put(EntityType.WITHER_SKULL, Material.WITHER_SKELETON_SKULL);
projectileItems.put(EntityType.FIREWORK_ROCKET, Material.FIREWORK_ROCKET); projectileItems.put(EntityType.FIREWORK, Material.FIREWORK_ROCKET);
nonFluidProofBlocks = new HashSet<>(); nonFluidProofBlocks = new HashSet<>();
nonFluidProofBlocks.addAll(carpets); nonFluidProofBlocks.addAll(carpets);
@ -504,22 +498,24 @@ public class BukkitUtils {
return diff.toArray(new ItemStack[diff.size()]); return diff.toArray(new ItemStack[diff.size()]);
} }
public static Collection<ItemStackAndAmount> compressInventory(ItemStack[] items) { public static ItemStack[] compressInventory(ItemStack[] items) {
final HashMap<ItemStack, Integer> compressed = new HashMap<>(); final ArrayList<ItemStack> compressed = new ArrayList<>();
for (final ItemStack item : items) { for (final ItemStack item : items) {
if (item != null && item.getType() != Material.AIR && item.getAmount() > 0) { if (item != null) {
int amount = item.getAmount(); boolean found = false;
ItemStack stack = item.clone(); for (final ItemStack item2 : compressed) {
stack.setAmount(1); if (item2.isSimilar(item)) {
Integer old = compressed.get(stack); item2.setAmount(item2.getAmount() + item.getAmount());
compressed.put(stack, (old == null ? 0 : old) + amount); found = true;
break;
}
}
if (!found) {
compressed.add(item.clone());
}
} }
} }
ArrayList<ItemStackAndAmount> result = new ArrayList<>(); return compressed.toArray(new ItemStack[compressed.size()]);
for (Entry<ItemStack, Integer> e : compressed.entrySet()) {
result.add(new ItemStackAndAmount(e.getKey(), e.getValue()));
}
return result;
} }
public static String friendlyWorldname(String worldName) { public static String friendlyWorldname(String worldName) {
@ -606,13 +602,15 @@ public class BukkitUtils {
return y; return y;
} }
public static int modifyContainer(BlockState b, ItemStackAndAmount item, boolean remove) { public static int modifyContainer(BlockState b, ItemStack item, boolean remove) {
if (item.amount() > 0 && b instanceof InventoryHolder c) { if (b instanceof InventoryHolder) {
final Inventory inv = c.getInventory(); final Inventory inv = ((InventoryHolder) b).getInventory();
if (remove) { if (remove) {
return InventoryUtils.removeFromInventory(inv, item); final ItemStack tmp = inv.removeItem(item).get(0);
} else { return tmp != null ? tmp.getAmount() : 0;
return InventoryUtils.addToInventory(inv, item); } else if (item.getAmount() > 0) {
final ItemStack tmp = inv.addItem(item).get(0);
return tmp != null ? tmp.getAmount() : 0;
} }
} }
return 0; return 0;
@ -658,16 +656,16 @@ public class BukkitUtils {
return m == Material.AIR || m == Material.CAVE_AIR || m == Material.VOID_AIR; return m == Material.AIR || m == Material.CAVE_AIR || m == Material.VOID_AIR;
} }
public static TextComponent toString(ItemStackAndAmount stack) { public static TextComponent toString(ItemStack stack) {
if (stack == null || stack.stack() == null || stack.amount() == 0 || isEmpty(stack.stack().getType())) { if (stack == null || stack.getAmount() == 0 || isEmpty(stack.getType())) {
return prettyMaterial("nothing"); return prettyMaterial("nothing");
} }
TextComponent msg = MessagingUtil.createTextComponentWithColor(stack.amount() + "x ", TypeColor.DEFAULT.getColor()); TextComponent msg = MessagingUtil.createTextComponentWithColor(stack.getAmount() + "x ", TypeColor.DEFAULT.getColor());
msg.addExtra(prettyMaterial(stack.stack().getType())); msg.addExtra(prettyMaterial(stack.getType()));
try { try {
String itemTag = stack.stack().getItemMeta().getAsString(); String itemTag = getItemTag(stack);
msg.setHoverEvent(new HoverEvent(Action.SHOW_ITEM, new Item(stack.stack().getType().getKey().toString(), 1, itemTag != null ? ItemTag.ofNbt(itemTag) : null))); msg.setHoverEvent(new HoverEvent(Action.SHOW_ITEM, new Item(stack.getType().getKey().toString(), 1, itemTag != null ? ItemTag.ofNbt(itemTag) : null)));
} catch (Exception e) { } catch (Exception e) {
LogBlock.getInstance().getLogger().log(Level.SEVERE, "Failed to convert Itemstack to JSON", e); LogBlock.getInstance().getLogger().log(Level.SEVERE, "Failed to convert Itemstack to JSON", e);
msg.setHoverEvent(new HoverEvent(Action.SHOW_TEXT, new Text(new BaseComponent[] { MessagingUtil.createTextComponentWithColor("Error", TypeColor.ERROR.getColor()) }))); msg.setHoverEvent(new HoverEvent(Action.SHOW_TEXT, new Text(new BaseComponent[] { MessagingUtil.createTextComponentWithColor("Error", TypeColor.ERROR.getColor()) })));
@ -676,6 +674,20 @@ public class BukkitUtils {
return msg; return msg;
} }
public static String getItemTag(ItemStack itemStack) throws ReflectiveOperationException {
Class<?> craftItemStackClazz = ReflectionUtil.getCraftBukkitClass("inventory.CraftItemStack");
Method asNMSCopyMethod = craftItemStackClazz.getMethod("asNMSCopy", ItemStack.class);
Class<?> nmsItemStackClazz = ReflectionUtil.getMinecraftClass("world.item.ItemStack");
Method getTagMethod = nmsItemStackClazz.getDeclaredMethod("getTagClone");
getTagMethod.setAccessible(true);
Object nmsItemStack = asNMSCopyMethod.invoke(null, itemStack);
Object itemTag = getTagMethod.invoke(nmsItemStack);
return itemTag != null ? itemTag.toString() : null;
}
public static String formatMinecraftKey(String s) { public static String formatMinecraftKey(String s) {
char[] cap = s.toCharArray(); char[] cap = s.toCharArray();
boolean lastSpace = true; boolean lastSpace = true;

View File

@ -1,113 +0,0 @@
package de.diddiz.LogBlock.util;
import org.bukkit.Material;
import org.bukkit.inventory.Inventory;
import org.bukkit.inventory.ItemStack;
public class InventoryUtils {
public static int addToInventory(Inventory inventory, ItemStackAndAmount item) {
if (item == null || item.stack() == null || item.stack().getType() == Material.AIR) {
return 0;
}
int maxStackSize = Math.max(Math.min(inventory.getMaxStackSize(), item.stack().getMaxStackSize()), 1);
ItemStack[] contents = inventory.getStorageContents();
int remaining = item.amount();
int initialRemaining = remaining;
// fill partial stacks
int firstPartial = -1;
while (remaining > 0) {
firstPartial = getFirstPartial(item.stack(), maxStackSize, contents, firstPartial + 1);
if (firstPartial < 0) {
break;
}
ItemStack content = contents[firstPartial];
int add = Math.min(maxStackSize - content.getAmount(), remaining);
content.setAmount(content.getAmount() + add);
remaining -= add;
}
// create new stacks
int firstFree = -1;
while (remaining > 0) {
firstFree = getFirstFree(contents, firstFree + 1);
if (firstFree < 0) {
break;
}
ItemStack content = item.stack().clone();
contents[firstFree] = content;
int add = Math.min(maxStackSize, remaining);
content.setAmount(add);
remaining -= add;
}
if (remaining < initialRemaining) {
inventory.setStorageContents(contents);
}
return remaining;
}
public static int removeFromInventory(Inventory inventory, ItemStackAndAmount item) {
if (item == null || item.stack() == null || item.stack().getType() == Material.AIR) {
return 0;
}
ItemStack[] contents = inventory.getStorageContents();
int remaining = item.amount();
int initialRemaining = remaining;
int firstSimilar = -1;
while (remaining > 0) {
firstSimilar = getFirstSimilar(item.stack(), contents, firstSimilar + 1);
if (firstSimilar < 0) {
break;
}
ItemStack content = contents[firstSimilar];
int here = content.getAmount();
if (here > remaining) {
content.setAmount(here - remaining);
remaining = 0;
} else {
contents[firstSimilar] = null;
remaining -= here;
}
}
if (remaining < initialRemaining) {
inventory.setStorageContents(contents);
}
return remaining;
}
private static int getFirstSimilar(ItemStack item, ItemStack[] contents, int start) {
for (int i = start; i < contents.length; i++) {
ItemStack content = contents[i];
if (content != null && content.isSimilar(item)) {
return i;
}
}
return -1;
}
private static int getFirstPartial(ItemStack item, int maxStackSize, ItemStack[] contents, int start) {
for (int i = start; i < contents.length; i++) {
ItemStack content = contents[i];
if (content != null && content.isSimilar(item) && content.getAmount() < maxStackSize) {
return i;
}
}
return -1;
}
private static int getFirstFree(ItemStack[] contents, int start) {
for (int i = start; i < contents.length; i++) {
ItemStack content = contents[i];
if (content == null || content.getAmount() == 0 || content.getType() == Material.AIR) {
return i;
}
}
return -1;
}
}

View File

@ -1,15 +0,0 @@
package de.diddiz.LogBlock.util;
import org.bukkit.inventory.ItemStack;
public record ItemStackAndAmount(ItemStack stack, int amount) {
public static ItemStackAndAmount fromStack(ItemStack stack) {
int amount = stack.getAmount();
if (amount > 1) {
stack = stack.clone();
stack.setAmount(1);
}
return new ItemStackAndAmount(stack, amount);
}
}

View File

@ -18,14 +18,10 @@ import org.bukkit.block.data.BlockData;
import org.bukkit.entity.EntityType; import org.bukkit.entity.EntityType;
public class MessagingUtil { public class MessagingUtil {
public static BaseComponent formatSummarizedChanges(int created, int destroyed, BaseComponent actor, int createdWidth, int destroyedWidth, float spaceFactor) { public static BaseComponent[] formatSummarizedChanges(int created, int destroyed, BaseComponent actor, int createdWidth, int destroyedWidth, float spaceFactor) {
TextComponent textCreated = createTextComponentWithColor(created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)), CREATE.getColor()); TextComponent textCreated = createTextComponentWithColor(created + spaces((int) ((10 - String.valueOf(created).length()) / spaceFactor)), CREATE.getColor());
TextComponent textDestroyed = createTextComponentWithColor(destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)), DESTROY.getColor()); TextComponent textDestroyed = createTextComponentWithColor(destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)), DESTROY.getColor());
TextComponent result = new TextComponent(); return new BaseComponent[] { textCreated, textDestroyed, actor };
result.addExtra(textCreated);
result.addExtra(textDestroyed);
result.addExtra(actor);
return result;
} }
public static TextComponent createTextComponentWithColor(String text, ChatColor color) { public static TextComponent createTextComponentWithColor(String text, ChatColor color) {

View File

@ -8,7 +8,6 @@ import com.google.gson.JsonObject;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL; import java.net.URL;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@ -46,7 +45,7 @@ public class UUIDFetcher {
} }
private static HttpURLConnection createConnection() throws Exception { private static HttpURLConnection createConnection() throws Exception {
URL url = new URI(PROFILE_URL).toURL(); URL url = new URL(PROFILE_URL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection(); HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST"); connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json"); connection.setRequestProperty("Content-Type", "application/json");

View File

@ -231,35 +231,20 @@ public class Utils {
return untrusted.replace("\\", "\\\\").replace("'", "\\'"); return untrusted.replace("\\", "\\\\").replace("'", "\\'");
} }
public static ItemStackAndAmount loadItemStack(byte[] data) { public static ItemStack loadItemStack(byte[] data) {
if (data == null || data.length == 0) { if (data == null || data.length == 0) {
return null; return null;
} }
YamlConfiguration conf = deserializeYamlConfiguration(data); YamlConfiguration conf = deserializeYamlConfiguration(data);
if (conf == null) { return conf == null ? null : conf.getItemStack("stack");
return null;
}
ItemStack stack = conf.getItemStack("stack");
if (stack == null) {
return null;
}
int amount = conf.contains("amount") ? conf.getInt("amount") : stack.getAmount();
stack.setAmount(1);
return new ItemStackAndAmount(stack, amount);
} }
public static byte[] saveItemStack(ItemStackAndAmount stack) { public static byte[] saveItemStack(ItemStack stack) {
if (stack == null || stack.stack() == null || BukkitUtils.isEmpty(stack.stack().getType())) { if (stack == null || BukkitUtils.isEmpty(stack.getType())) {
return null; return null;
} }
YamlConfiguration conf = new YamlConfiguration(); YamlConfiguration conf = new YamlConfiguration();
ItemStack itemStack = stack.stack(); conf.set("stack", stack);
if (itemStack.getAmount() > 1) {
itemStack = itemStack.clone();
itemStack.setAmount(1);
}
conf.set("stack", itemStack);
conf.set("amount", stack.amount());
return serializeYamlConfiguration(conf); return serializeYamlConfiguration(conf);
} }

View File

@ -2,10 +2,10 @@ package de.diddiz.LogBlock.worldedit;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.UUID; import java.util.UUID;
import java.util.logging.Level; import java.util.logging.Level;
@ -17,15 +17,15 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player; import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin; import org.bukkit.plugin.Plugin;
import org.bukkit.util.BlockVector; import org.bukkit.util.BlockVector;
import org.enginehub.linbus.stream.LinBinaryIO; import com.sk89q.jnbt.CompoundTag;
import org.enginehub.linbus.stream.LinStream; import com.sk89q.jnbt.DoubleTag;
import org.enginehub.linbus.tree.LinCompoundTag; import com.sk89q.jnbt.FloatTag;
import org.enginehub.linbus.tree.LinDoubleTag; import com.sk89q.jnbt.ListTag;
import org.enginehub.linbus.tree.LinIntArrayTag; import com.sk89q.jnbt.NBTInputStream;
import org.enginehub.linbus.tree.LinListTag; import com.sk89q.jnbt.NBTOutputStream;
import org.enginehub.linbus.tree.LinLongTag; import com.sk89q.jnbt.NamedTag;
import org.enginehub.linbus.tree.LinRootEntry; import com.sk89q.jnbt.ShortTag;
import org.enginehub.linbus.tree.LinTagType; import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.IncompleteRegionException; import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession; import com.sk89q.worldedit.LocalSession;
import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitAdapter;
@ -33,7 +33,6 @@ import com.sk89q.worldedit.bukkit.WorldEditPlugin;
import com.sk89q.worldedit.entity.BaseEntity; import com.sk89q.worldedit.entity.BaseEntity;
import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.math.BlockVector3;
import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.concurrency.LazyReference;
import de.diddiz.LogBlock.LogBlock; import de.diddiz.LogBlock.LogBlock;
import de.diddiz.LogBlock.util.CuboidRegion; import de.diddiz.LogBlock.util.CuboidRegion;
@ -108,25 +107,21 @@ public class WorldEditHelper {
com.sk89q.worldedit.world.entity.EntityType weType = BukkitAdapter.adapt(type); com.sk89q.worldedit.world.entity.EntityType weType = BukkitAdapter.adapt(type);
com.sk89q.worldedit.util.Location weLocation = BukkitAdapter.adapt(location); com.sk89q.worldedit.util.Location weLocation = BukkitAdapter.adapt(location);
try { try {
LinStream stream = LinBinaryIO.read(new DataInputStream(new ByteArrayInputStream(serialized))); NBTInputStream nbtis = new NBTInputStream(new ByteArrayInputStream(serialized));
LinRootEntry namedTag = LinRootEntry.readFrom(stream); NamedTag namedTag = nbtis.readNamedTag();
nbtis.close();
UUID newUUID = null; UUID newUUID = null;
if (namedTag.name().equals("entity")) { if (namedTag.getName().equals("entity") && namedTag.getTag() instanceof CompoundTag) {
LinCompoundTag serializedState = namedTag.value(); CompoundTag serializedState = (CompoundTag) namedTag.getTag();
BaseEntity state = new BaseEntity(weType, LazyReference.computed(serializedState)); BaseEntity state = new BaseEntity(weType, serializedState);
com.sk89q.worldedit.entity.Entity weEntity = weLocation.getExtent().createEntity(weLocation, state); com.sk89q.worldedit.entity.Entity weEntity = weLocation.getExtent().createEntity(weLocation, state);
if (weEntity != null) { if (weEntity != null) {
LinCompoundTag newNbt = weEntity.getState().getNbt(); CompoundTag newNbt = weEntity.getState().getNbtData();
LinIntArrayTag uuidTag = newNbt.findTag("UUID", LinTagType.intArrayTag()); int[] uuidInts = newNbt.getIntArray("UUID");
int[] uuidInts = uuidTag == null ? null : uuidTag.value();
if (uuidInts != null && uuidInts.length >= 4) { if (uuidInts != null && uuidInts.length >= 4) {
newUUID = new UUID(((long) uuidInts[0] << 32) | (uuidInts[1] & 0xFFFFFFFFL), ((long) uuidInts[2] << 32) | (uuidInts[3] & 0xFFFFFFFFL)); newUUID = new UUID(((long) uuidInts[0] << 32) | (uuidInts[1] & 0xFFFFFFFFL), ((long) uuidInts[2] << 32) | (uuidInts[3] & 0xFFFFFFFFL));
} else { } else {
LinLongTag uuidMostTag = newNbt.findTag("UUIDMost", LinTagType.longTag()); newUUID = new UUID(newNbt.getLong("UUIDMost"), newNbt.getLong("UUIDLeast")); // pre 1.16
LinLongTag uuidLeastTag = newNbt.findTag("UUIDLeast", LinTagType.longTag());
if (uuidMostTag != null && uuidLeastTag != null) {
newUUID = new UUID(uuidMostTag.valueAsLong(), uuidLeastTag.valueAsLong()); // pre 1.16
}
} }
} }
} }
@ -141,18 +136,16 @@ public class WorldEditHelper {
BaseEntity state = weEntity.getState(); BaseEntity state = weEntity.getState();
if (state != null) { if (state != null) {
try { try {
LinCompoundTag.Builder nbt = state.getNbt().toBuilder();
nbt.putFloat("Health", 20.0f);
nbt.put("Motion", LinListTag.builder(LinTagType.doubleTag()).add(LinDoubleTag.of(0)).add(LinDoubleTag.of(0)).add(LinDoubleTag.of(0)).build());
nbt.putShort("Fire", (short) -20);
nbt.putShort("HurtTime", (short) 0);
LinRootEntry root = new LinRootEntry("entity", nbt.build());
ByteArrayOutputStream baos = new ByteArrayOutputStream(); ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (DataOutputStream dos = new DataOutputStream(baos)) { NBTOutputStream nbtos = new NBTOutputStream(baos);
LinBinaryIO.write(dos, root); CompoundTag nbt = state.getNbtData();
} LinkedHashMap<String, Tag<?, ?>> value = new LinkedHashMap<>(nbt.getValue());
value.put("Health", new FloatTag(20.0f));
value.put("Motion", new ListTag(DoubleTag.class, Arrays.asList(new DoubleTag[] { new DoubleTag(0), new DoubleTag(0), new DoubleTag(0) })));
value.put("Fire", new ShortTag((short) -20));
value.put("HurtTime", new ShortTag((short) 0));
nbtos.writeNamedTag("entity", new CompoundTag(value));
nbtos.close();
return baos.toByteArray(); return baos.toByteArray();
} catch (IOException e) { } catch (IOException e) {
throw new RuntimeException("This IOException should be impossible", e); throw new RuntimeException("This IOException should be impossible", e);
@ -182,7 +175,7 @@ public class WorldEditHelper {
} }
BlockVector3 min = selection.getMinimumPoint(); BlockVector3 min = selection.getMinimumPoint();
BlockVector3 max = selection.getMaximumPoint(); BlockVector3 max = selection.getMaximumPoint();
return new CuboidRegion(world, new BlockVector(min.x(), min.y(), min.z()), new BlockVector(max.x(), max.y(), max.z())); return new CuboidRegion(world, new BlockVector(min.getBlockX(), min.getBlockY(), min.getBlockZ()), new BlockVector(max.getBlockX(), max.getBlockY(), max.getBlockZ()));
} }
} }
} }