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>
<groupId>org.spigotmc</groupId>
<artifactId>spigot-api</artifactId>
<version>1.21.5-R0.1-SNAPSHOT</version>
<version>1.20.4-R0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
<dependency>
@ -125,9 +125,9 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.13.0</version>
<version>3.12.1</version>
<configuration>
<release>21</release>
<release>17</release>
</configuration>
</plugin>
<plugin>
@ -153,7 +153,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.5.3</version>
<version>3.5.1</version>
<configuration>
</configuration>
<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.util.BukkitUtils;
import de.diddiz.LogBlock.util.ItemStackAndAmount;
import de.diddiz.LogBlock.util.Utils;
import java.sql.ResultSet;
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.Switch;
import org.bukkit.block.data.type.WallSign;
import org.bukkit.inventory.ItemStack;
public class BlockChange implements LookupCacheElement {
public final long id, date;
@ -75,7 +75,7 @@ public class BlockChange implements LookupCacheElement {
typeState = p.needType ? rs.getBytes("typeState") : null;
ChestAccess catemp = null;
if (p.needChestAccess) {
ItemStackAndAmount stack = Utils.loadItemStack(rs.getBytes("item"));
ItemStack stack = Utils.loadItemStack(rs.getBytes("item"));
if (stack != null) {
catemp = new ChestAccess(stack, rs.getBoolean("itemremove"), rs.getInt("itemtype"));
}
@ -113,7 +113,7 @@ public class BlockChange implements LookupCacheElement {
}
@Override
public BaseComponent getLogMessage(int entry) {
public BaseComponent[] getLogMessage(int entry) {
TextComponent msg = new TextComponent();
if (date > 0) {
msg.addExtra(prettyDate(date));
@ -127,7 +127,7 @@ public class BlockChange implements LookupCacheElement {
BlockData replaced = getBlockReplaced();
if (type == null || replaced == null) {
msg.addExtra("did an unknown block modification");
return msg;
return new BaseComponent[] { msg };
}
// Process type details once for later use.
@ -254,7 +254,7 @@ public class BlockChange implements LookupCacheElement {
msg.addExtra(" at ");
msg.addExtra(prettyLocation(loc, entry));
}
return msg;
return new BaseComponent[] { msg };
}
public BlockData getBlockReplaced() {

View File

@ -39,7 +39,7 @@ public class ChatMessage implements LookupCacheElement {
}
@Override
public BaseComponent getLogMessage(int entry) {
public BaseComponent[] getLogMessage(int entry) {
TextComponent msg = new TextComponent();
if (date > 0) {
msg.addExtra(prettyDate(date));
@ -50,8 +50,10 @@ public class ChatMessage implements LookupCacheElement {
msg.addExtra(" ");
}
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;
import de.diddiz.LogBlock.util.ItemStackAndAmount;
import org.bukkit.inventory.ItemStack;
public class ChestAccess {
public final ItemStackAndAmount itemStack;
public final ItemStack itemStack;
public final boolean remove;
public final int itemType;
public ChestAccess(ItemStackAndAmount itemStack, boolean remove, int itemType) {
public ChestAccess(ItemStack itemStack, boolean remove, int itemType) {
this.itemStack = itemStack;
this.remove = remove;
this.itemType = itemType;

View File

@ -443,7 +443,9 @@ public class CommandsHandler implements CommandExecutor {
if (lookupElements[i].getLocation() != null) {
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);
}
if (setSessionPage) {

View File

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

View File

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

View File

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

View File

@ -101,11 +101,19 @@ public class LogBlock extends JavaPlugin {
return;
}
final Statement st = conn.createStatement();
final ResultSet rs = st.executeQuery("SHOW CHARACTER SET where charset='utf8mb4';");
if (rs.next()) {
Config.mb4 = true;
// Allegedly JDBC driver since 2010 hasn't needed this. I did.
st.executeUpdate("SET NAMES utf8mb4;");
try {
final ResultSet rs = st.executeQuery("SHOW CHARACTER SET where charset='utf8mb4';");
if (rs.next()) {
Config.mb4 = true;
// 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();
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)) {
pm.registerEvents(new ChatLogging(this), this);
}
if (isLogging(Logging.WITHER) || isLogging(Logging.ENDERMEN)) {
pm.registerEvents(new EntityChangeBlockLogging(this), this);
if (isLogging(Logging.ENDERMEN)) {
pm.registerEvents(new EndermenLogging(this), this);
}
if (isLogging(Logging.WITHER)) {
pm.registerEvents(new WitherLogging(this), this);
}
if (isLogging(Logging.NATURALSTRUCTUREGROW)) {
pm.registerEvents(new StructureGrowLogging(this), this);

View File

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

View File

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

View File

@ -32,7 +32,7 @@ public class SummedBlockChanges implements LookupCacheElement {
}
@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);
}

View File

@ -33,7 +33,7 @@ public class SummedEntityChanges implements LookupCacheElement {
}
@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);
}

View File

@ -25,7 +25,7 @@ public class SummedKills implements LookupCacheElement {
}
@Override
public BaseComponent getLogMessage(int entry) {
public BaseComponent[] getLogMessage(int entry) {
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.WorldConfig;
import de.diddiz.LogBlock.util.ComparableVersion;
import de.diddiz.LogBlock.util.ItemStackAndAmount;
import de.diddiz.LogBlock.util.UUIDFetcher;
import de.diddiz.LogBlock.util.Utils;
import org.bukkit.Bukkit;
@ -535,7 +534,7 @@ class Updater {
@SuppressWarnings("deprecation")
ItemStack stack = weaponMaterial.getMaxDurability() > 0 ? new ItemStack(weaponMaterial, Math.abs(amount), (short) itemdata) : new ItemStack(weaponMaterial, Math.abs(amount));
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(4, MaterialConverter.getOrAddMaterialId(weaponMaterial));
insertChestData.addBatch();
@ -870,49 +869,150 @@ class Updater {
}
final Statement state = conn.createStatement();
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
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()) {
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)) {
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) {
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-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);
createTable(state, "lb-materials",
"id INT UNSIGNED NOT NULL, " +
"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()) {
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 + "-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))");
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 + "-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)) {
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 + "-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))");
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 + "-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();
conn.close();
}
private void createTable(Statement state, String table, String query) throws SQLException {
try (ResultSet tableResult = state.executeQuery("SHOW TABLES LIKE '" + table + "'")) {
if (!tableResult.next()) {
logblock.getLogger().log(Level.INFO, "Creating table " + table + ".");
state.execute("CREATE TABLE `" + table + "` " + query);
try (ResultSet tableResultNew = state.executeQuery("SHOW TABLES LIKE '" + table + "'")) {
if (!tableResultNew.next()) {
throw new SQLException("Table " + table + " not found and failed to create");
}
}
}
}
private void createTable(Statement state, String table, String columns, String additional) throws SQLException {
logblock.getLogger().log(Level.INFO, "Creating table " + table + ".");
String sql = "CREATE TABLE IF NOT EXISTS \"" + table + "\" (" +
(
columns
.replace("INT UNSIGNED NOT NULL AUTO_INCREMENT", "SERIAL NOT NULL")
.replace("INT UNSIGNED", "INT")
.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.ItemFrame;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import de.diddiz.LogBlock.QueryParams.Order;
@ -36,7 +35,6 @@ import java.io.File;
import java.io.PrintWriter;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
@ -55,8 +53,6 @@ import static de.diddiz.LogBlock.util.BukkitUtils.*;
public class WorldEditor implements Runnable {
private final LogBlock logblock;
private final ArrayList<Edit> edits = new ArrayList<>();
private int rowsCompleted;
private int totalRows;
private final World world;
/**
@ -139,7 +135,6 @@ public class WorldEditor implements Runnable {
}
started = true;
final long start = System.currentTimeMillis();
totalRows = edits.size();
taskID = logblock.getServer().getScheduler().scheduleSyncRepeatingTask(logblock, this, 0, 1);
if (taskID == -1) {
throw new Exception("Failed to schedule task");
@ -156,9 +151,8 @@ public class WorldEditor implements Runnable {
public synchronized void run() {
final List<WorldEditorException> errorList = new ArrayList<>();
int counter = 0;
long t0 = System.nanoTime();
long maxEditTime = 5_000_000; // 5 ms
while (!edits.isEmpty() && counter < 10000 && (counter < 100 || counter % 10 != 0 || System.nanoTime() - t0 < maxEditTime)) {
float size = edits.size();
while (!edits.isEmpty() && counter < 100) {
try {
switch (edits.remove(edits.size() - 1).perform()) {
case SUCCESS:
@ -175,12 +169,11 @@ public class WorldEditor implements Runnable {
} catch (final Exception ex) {
logblock.getLogger().log(Level.WARNING, "[WorldEditor] Exeption: ", ex);
}
rowsCompleted++;
counter++;
if (sender != null) {
float percentage = rowsCompleted * 100.0f / totalRows;
if (rowsCompleted % 10000 == 0) {
sender.sendMessage(ChatColor.GOLD + "[LogBlock]" + ChatColor.YELLOW + " Rollback progress: " + NumberFormat.getNumberInstance().format(percentage) + "%" +
float percentage = ((size - edits.size()) / size) * 100.0F;
if (percentage % 20 == 0) {
sender.sendMessage(ChatColor.GOLD + "[LogBlock]" + ChatColor.YELLOW + " Rollback progress: " + percentage + "%" +
" Blocks edited: " + counter);
}
}
@ -375,10 +368,10 @@ public class WorldEditor implements Runnable {
BlockState state = block.getState();
if (setBlock.equals(replacedBlock)) {
if (ca != null) {
if (state instanceof InventoryHolder && state.getType() == replacedBlock.getMaterial()) {
if (state instanceof Container && state.getType() == replacedBlock.getMaterial()) {
int leftover;
try {
leftover = modifyContainer(state, ca.itemStack, !ca.remove);
leftover = modifyContainer(state, new ItemStack(ca.itemStack), !ca.remove);
} catch (final Exception ex) {
throw new WorldEditorException(ex.getMessage(), block.getLocation());
}
@ -493,8 +486,8 @@ public class WorldEditor implements Runnable {
}
@Override
public BaseComponent getLogMessage(int entry) {
return TextComponent.fromLegacy(getMessage());
public BaseComponent[] getLogMessage(int entry) {
return TextComponent.fromLegacyText(getMessage());
}
}
}

View File

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

View File

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

View File

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

View File

@ -7,8 +7,8 @@ import java.util.List;
import org.bukkit.entity.EntityType;
public enum EntityLogging {
SPAWN(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.SNOW_GOLEM.name() }),
DESTROY(new String[] { EntityType.ARMOR_STAND.name(), EntityType.ITEM_FRAME.name(), EntityType.VILLAGER.name(), EntityType.SNOW_GOLEM.name(), "ANIMAL" }),
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.SNOWMAN.name(), "ANIMAL" }),
MODIFY(new String[] { "ALL" });
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.Material;
import org.bukkit.NamespacedKey;
import org.bukkit.block.BlockFace;
import org.bukkit.configuration.file.YamlConfiguration;
import org.bukkit.entity.ArmorStand;
@ -193,17 +192,18 @@ public class AdvancedEntityLogging extends LoggingListener {
LivingEntity entity = event.getEntity();
if (Config.isLogging(entity.getWorld(), EntityLogging.DESTROY, entity)) {
Actor actor = null;
Entity cause = event.getDamageSource().getCausingEntity();
Entity damager = LoggingUtil.getRealDamager(cause);
if (damager != null) {
actor = Actor.actorFromEntity(damager);
EntityDamageEvent lastDamage = entity.getLastDamageCause();
if (lastDamage instanceof EntityDamageByEntityEvent) {
Entity damager = LoggingUtil.getRealDamager(((EntityDamageByEntityEvent) lastDamage).getDamager());
if (damager != null) {
actor = Actor.actorFromEntity(damager);
}
}
if (actor == null && entity.getKiller() != null) {
actor = Actor.actorFromEntity(entity.getKiller());
}
if (actor == null) {
NamespacedKey key = event.getDamageSource().getDamageType().getKey();
actor = new Actor(key == null ? "unknown" : key.getKey().toUpperCase());
actor = new Actor(lastDamage == null ? "UNKNOWN" : lastDamage.getCause().toString());
}
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.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.util.ItemStackAndAmount;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.DecoratedPot;
import org.bukkit.block.DoubleChest;
import org.bukkit.block.data.type.ChiseledBookshelf;
import org.bukkit.entity.HumanEntity;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.inventory.ClickType;
import org.bukkit.event.inventory.InventoryClickEvent;
import org.bukkit.event.inventory.InventoryCloseEvent;
import org.bukkit.event.inventory.InventoryDragEvent;
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.InventoryHolder;
import org.bukkit.inventory.ItemStack;
import org.bukkit.util.Vector;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
@ -79,10 +69,9 @@ public class ChestAccessLogging extends LoggingListener {
for (Entry<ItemStack, Integer> e : modifications.entrySet()) {
ItemStack stack = e.getKey();
int amount = e.getValue();
if (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);
}
stack.setAmount(Math.abs(amount));
// consumer.getLogblock().getLogger().info("Store container: " + stack + " take: " + (amount < 0));
consumer.queueChestAccess(Actor.actorFromEntity(actor), location, location.getWorld().getBlockAt(location).getBlockData(), stack, amount < 0);
}
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.util.BukkitUtils;
import org.bukkit.Bukkit;
import org.bukkit.ExplosionResult;
import org.bukkit.Location;
import org.bukkit.Material;
import org.bukkit.block.Block;
@ -42,9 +41,6 @@ public class ExplosionLogging extends LoggingListener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityExplode(EntityExplodeEvent event) {
if (event.getExplosionResult() == ExplosionResult.KEEP || event.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK) {
return;
}
final WorldConfig wcfg = getWorldConfig(event.getLocation().getWorld());
if (wcfg != null) {
Actor actor = new Actor("Explosion");
@ -178,9 +174,6 @@ public class ExplosionLogging extends LoggingListener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onBlockExplode(BlockExplodeEvent event) {
if (event.getExplosionResult() == ExplosionResult.KEEP || event.getExplosionResult() == ExplosionResult.TRIGGER_BLOCK) {
return;
}
Player bedCause = null;
if (lastBedInteractionPlayer != null && lastBedInteractionLocation != null) {
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.Logging;
import de.diddiz.LogBlock.config.Config.*;
import org.bukkit.NamespacedKey;
import org.bukkit.entity.Entity;
import org.bukkit.entity.LivingEntity;
import org.bukkit.entity.Monster;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.entity.EntityDamageByEntityEvent;
import org.bukkit.event.entity.EntityDamageEvent;
import org.bukkit.event.entity.EntityDeathEvent;
import static de.diddiz.LogBlock.config.Config.*;
@ -23,26 +24,27 @@ public class KillLogging extends LoggingListener {
@EventHandler(priority = EventPriority.MONITOR, ignoreCancelled = true)
public void onEntityDeath(EntityDeathEvent deathEvent) {
if (isLogging(deathEvent.getEntity().getWorld(), Logging.KILL)) {
LivingEntity victim = deathEvent.getEntity();
Entity killer = deathEvent.getDamageSource().getCausingEntity();
if (killer != null) {
EntityDamageEvent event = deathEvent.getEntity().getLastDamageCause();
// For a death event, there should always be a damage event and it should not be cancelled. Check anyway.
if (event != null && event.isCancelled() == false && isLogging(event.getEntity().getWorld(), Logging.KILL) && event.getEntity() instanceof LivingEntity) {
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)) {
return;
} else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster) && killer instanceof Player || killer instanceof Monster)) {
return;
}
consumer.queueKill(killer, victim);
} else if (deathEvent.getEntity().getKiller() != null) {
consumer.queueKill(deathEvent.getEntity().getKiller(), victim);
} else if (logEnvironmentalKills) {
if (logKillsLevel == LogKillsLevel.PLAYERS && !(victim instanceof Player)) {
return;
} else if (logKillsLevel == LogKillsLevel.MONSTERS && !((victim instanceof Player || victim instanceof Monster))) {
return;
}
NamespacedKey key = deathEvent.getDamageSource().getDamageType().getKey();
Actor actor = new Actor(key == null ? "unknown" : key.getKey().toUpperCase());
consumer.queueKill(actor, victim);
consumer.queueKill(new Actor(event.getCause().toString()), victim);
}
}
}

View File

@ -1,24 +1,18 @@
package de.diddiz.LogBlock.listeners;
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.LogBlock;
import de.diddiz.LogBlock.Logging;
import de.diddiz.LogBlock.config.WorldConfig;
import org.bukkit.Bukkit;
import org.bukkit.Material;
import org.bukkit.Tag;
import org.bukkit.block.Block;
import org.bukkit.block.BlockState;
import org.bukkit.block.Lectern;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.block.Action;
import org.bukkit.event.player.PlayerInteractEvent;
import org.bukkit.event.block.BlockPlaceEvent;
import org.bukkit.event.player.PlayerTakeLecternBookEvent;
import org.bukkit.inventory.EquipmentSlot;
import org.bukkit.inventory.ItemStack;
public class LecternLogging extends LoggingListener {
@ -27,31 +21,25 @@ public class LecternLogging 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.LECTERNBOOKCHANGE)) {
return;
}
final Material type = clicked.getType();
if (type == Material.LECTERN) {
ItemStack mainHand = player.getInventory().getItemInMainHand();
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);
if (currentInLectern == null || currentInLectern.getType() == Material.AIR) {
ItemStack stack = mainHand.clone();
stack.setAmount(1);
Lectern newLectern = (Lectern) clicked.getState();
newLectern.getSnapshotInventory().setItem(0, stack);
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);
public void onBlockPlace(BlockPlaceEvent event) {
final WorldConfig wcfg = getWorldConfig(event.getPlayer().getWorld());
if (wcfg != null && wcfg.isLogging(Logging.LECTERNBOOKCHANGE)) {
final BlockState before = event.getBlockReplacedState();
final BlockState after = event.getBlockPlaced().getState();
if (before.getType() == Material.LECTERN && after.getType() == Material.LECTERN) {
Lectern lecternBefore = (Lectern) before.getBlock().getState();
ItemStack book = lecternBefore.getSnapshotInventory().getItem(0);
try {
lecternBefore.getSnapshotInventory().setItem(0, null);
} catch (NullPointerException e) {
//ignored
}
lecternBefore.setBlockData(before.getBlockData());
consumer.queueBlockReplace(Actor.actorFromEntity(event.getPlayer()), lecternBefore, after);
try {
lecternBefore.getSnapshotInventory().setItem(0, book);
} catch (NullPointerException e) {
//ignored
}
}
}

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 java.io.File;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.Set;
import java.util.UUID;
@ -148,11 +147,8 @@ public class BukkitUtils {
// https://minecraft.fandom.com/wiki/Tag#blocks_small_flowers
Set<Material> smallFlowers = Tag.SMALL_FLOWERS.getValues();
Set<Material> tallFlowers = Set.of(Material.SUNFLOWER,
Material.LILAC,
Material.PEONY,
Material.ROSE_BUSH,
Material.PITCHER_PLANT);
// https://minecraft.fandom.com/wiki/Tag#blocks_tall_flowers
Set<Material> tallFlowers = Tag.TALL_FLOWERS.getValues();
Set<Material> bannerStanding = Set.of(Material.WHITE_BANNER,
Material.ORANGE_BANNER,
@ -335,7 +331,6 @@ public class BukkitUtils {
containerBlocks.add(Material.BLAST_FURNACE);
containerBlocks.add(Material.SMOKER);
containerBlocks.add(Material.CHISELED_BOOKSHELF);
containerBlocks.add(Material.DECORATED_POT);
// Doesn't actually have a block inventory
// containerBlocks.add(Material.ENDER_CHEST);
@ -346,13 +341,12 @@ public class BukkitUtils {
projectileItems.put(EntityType.ENDER_PEARL, Material.ENDER_PEARL);
projectileItems.put(EntityType.SMALL_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.SPLASH_POTION, Material.SPLASH_POTION);
projectileItems.put(EntityType.LINGERING_POTION, Material.LINGERING_POTION);
projectileItems.put(EntityType.EXPERIENCE_BOTTLE, Material.EXPERIENCE_BOTTLE);
projectileItems.put(EntityType.THROWN_EXP_BOTTLE, Material.EXPERIENCE_BOTTLE);
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.addAll(carpets);
@ -504,22 +498,24 @@ public class BukkitUtils {
return diff.toArray(new ItemStack[diff.size()]);
}
public static Collection<ItemStackAndAmount> compressInventory(ItemStack[] items) {
final HashMap<ItemStack, Integer> compressed = new HashMap<>();
public static ItemStack[] compressInventory(ItemStack[] items) {
final ArrayList<ItemStack> compressed = new ArrayList<>();
for (final ItemStack item : items) {
if (item != null && item.getType() != Material.AIR && item.getAmount() > 0) {
int amount = item.getAmount();
ItemStack stack = item.clone();
stack.setAmount(1);
Integer old = compressed.get(stack);
compressed.put(stack, (old == null ? 0 : old) + amount);
if (item != null) {
boolean found = false;
for (final ItemStack item2 : compressed) {
if (item2.isSimilar(item)) {
item2.setAmount(item2.getAmount() + item.getAmount());
found = true;
break;
}
}
if (!found) {
compressed.add(item.clone());
}
}
}
ArrayList<ItemStackAndAmount> result = new ArrayList<>();
for (Entry<ItemStack, Integer> e : compressed.entrySet()) {
result.add(new ItemStackAndAmount(e.getKey(), e.getValue()));
}
return result;
return compressed.toArray(new ItemStack[compressed.size()]);
}
public static String friendlyWorldname(String worldName) {
@ -606,13 +602,15 @@ public class BukkitUtils {
return y;
}
public static int modifyContainer(BlockState b, ItemStackAndAmount item, boolean remove) {
if (item.amount() > 0 && b instanceof InventoryHolder c) {
final Inventory inv = c.getInventory();
public static int modifyContainer(BlockState b, ItemStack item, boolean remove) {
if (b instanceof InventoryHolder) {
final Inventory inv = ((InventoryHolder) b).getInventory();
if (remove) {
return InventoryUtils.removeFromInventory(inv, item);
} else {
return InventoryUtils.addToInventory(inv, item);
final ItemStack tmp = inv.removeItem(item).get(0);
return tmp != null ? tmp.getAmount() : 0;
} else if (item.getAmount() > 0) {
final ItemStack tmp = inv.addItem(item).get(0);
return tmp != null ? tmp.getAmount() : 0;
}
}
return 0;
@ -658,16 +656,16 @@ public class BukkitUtils {
return m == Material.AIR || m == Material.CAVE_AIR || m == Material.VOID_AIR;
}
public static TextComponent toString(ItemStackAndAmount stack) {
if (stack == null || stack.stack() == null || stack.amount() == 0 || isEmpty(stack.stack().getType())) {
public static TextComponent toString(ItemStack stack) {
if (stack == null || stack.getAmount() == 0 || isEmpty(stack.getType())) {
return prettyMaterial("nothing");
}
TextComponent msg = MessagingUtil.createTextComponentWithColor(stack.amount() + "x ", TypeColor.DEFAULT.getColor());
msg.addExtra(prettyMaterial(stack.stack().getType()));
TextComponent msg = MessagingUtil.createTextComponentWithColor(stack.getAmount() + "x ", TypeColor.DEFAULT.getColor());
msg.addExtra(prettyMaterial(stack.getType()));
try {
String itemTag = stack.stack().getItemMeta().getAsString();
msg.setHoverEvent(new HoverEvent(Action.SHOW_ITEM, new Item(stack.stack().getType().getKey().toString(), 1, itemTag != null ? ItemTag.ofNbt(itemTag) : null)));
String itemTag = getItemTag(stack);
msg.setHoverEvent(new HoverEvent(Action.SHOW_ITEM, new Item(stack.getType().getKey().toString(), 1, itemTag != null ? ItemTag.ofNbt(itemTag) : null)));
} catch (Exception 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()) })));
@ -676,6 +674,20 @@ public class BukkitUtils {
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) {
char[] cap = s.toCharArray();
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;
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 textDestroyed = createTextComponentWithColor(destroyed + spaces((int) ((10 - String.valueOf(destroyed).length()) / spaceFactor)), DESTROY.getColor());
TextComponent result = new TextComponent();
result.addExtra(textCreated);
result.addExtra(textDestroyed);
result.addExtra(actor);
return result;
return new BaseComponent[] { textCreated, textDestroyed, actor };
}
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.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
@ -46,7 +45,7 @@ public class UUIDFetcher {
}
private static HttpURLConnection createConnection() throws Exception {
URL url = new URI(PROFILE_URL).toURL();
URL url = new URL(PROFILE_URL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Content-Type", "application/json");

View File

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

View File

@ -2,10 +2,10 @@ package de.diddiz.LogBlock.worldedit;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.UUID;
import java.util.logging.Level;
@ -17,15 +17,15 @@ import org.bukkit.entity.EntityType;
import org.bukkit.entity.Player;
import org.bukkit.plugin.Plugin;
import org.bukkit.util.BlockVector;
import org.enginehub.linbus.stream.LinBinaryIO;
import org.enginehub.linbus.stream.LinStream;
import org.enginehub.linbus.tree.LinCompoundTag;
import org.enginehub.linbus.tree.LinDoubleTag;
import org.enginehub.linbus.tree.LinIntArrayTag;
import org.enginehub.linbus.tree.LinListTag;
import org.enginehub.linbus.tree.LinLongTag;
import org.enginehub.linbus.tree.LinRootEntry;
import org.enginehub.linbus.tree.LinTagType;
import com.sk89q.jnbt.CompoundTag;
import com.sk89q.jnbt.DoubleTag;
import com.sk89q.jnbt.FloatTag;
import com.sk89q.jnbt.ListTag;
import com.sk89q.jnbt.NBTInputStream;
import com.sk89q.jnbt.NBTOutputStream;
import com.sk89q.jnbt.NamedTag;
import com.sk89q.jnbt.ShortTag;
import com.sk89q.jnbt.Tag;
import com.sk89q.worldedit.IncompleteRegionException;
import com.sk89q.worldedit.LocalSession;
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.math.BlockVector3;
import com.sk89q.worldedit.regions.Region;
import com.sk89q.worldedit.util.concurrency.LazyReference;
import de.diddiz.LogBlock.LogBlock;
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.util.Location weLocation = BukkitAdapter.adapt(location);
try {
LinStream stream = LinBinaryIO.read(new DataInputStream(new ByteArrayInputStream(serialized)));
LinRootEntry namedTag = LinRootEntry.readFrom(stream);
NBTInputStream nbtis = new NBTInputStream(new ByteArrayInputStream(serialized));
NamedTag namedTag = nbtis.readNamedTag();
nbtis.close();
UUID newUUID = null;
if (namedTag.name().equals("entity")) {
LinCompoundTag serializedState = namedTag.value();
BaseEntity state = new BaseEntity(weType, LazyReference.computed(serializedState));
if (namedTag.getName().equals("entity") && namedTag.getTag() instanceof CompoundTag) {
CompoundTag serializedState = (CompoundTag) namedTag.getTag();
BaseEntity state = new BaseEntity(weType, serializedState);
com.sk89q.worldedit.entity.Entity weEntity = weLocation.getExtent().createEntity(weLocation, state);
if (weEntity != null) {
LinCompoundTag newNbt = weEntity.getState().getNbt();
LinIntArrayTag uuidTag = newNbt.findTag("UUID", LinTagType.intArrayTag());
int[] uuidInts = uuidTag == null ? null : uuidTag.value();
CompoundTag newNbt = weEntity.getState().getNbtData();
int[] uuidInts = newNbt.getIntArray("UUID");
if (uuidInts != null && uuidInts.length >= 4) {
newUUID = new UUID(((long) uuidInts[0] << 32) | (uuidInts[1] & 0xFFFFFFFFL), ((long) uuidInts[2] << 32) | (uuidInts[3] & 0xFFFFFFFFL));
} else {
LinLongTag uuidMostTag = newNbt.findTag("UUIDMost", LinTagType.longTag());
LinLongTag uuidLeastTag = newNbt.findTag("UUIDLeast", LinTagType.longTag());
if (uuidMostTag != null && uuidLeastTag != null) {
newUUID = new UUID(uuidMostTag.valueAsLong(), uuidLeastTag.valueAsLong()); // pre 1.16
}
newUUID = new UUID(newNbt.getLong("UUIDMost"), newNbt.getLong("UUIDLeast")); // pre 1.16
}
}
}
@ -141,18 +136,16 @@ public class WorldEditHelper {
BaseEntity state = weEntity.getState();
if (state != null) {
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();
try (DataOutputStream dos = new DataOutputStream(baos)) {
LinBinaryIO.write(dos, root);
}
NBTOutputStream nbtos = new NBTOutputStream(baos);
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();
} catch (IOException e) {
throw new RuntimeException("This IOException should be impossible", e);
@ -182,7 +175,7 @@ public class WorldEditHelper {
}
BlockVector3 min = selection.getMinimumPoint();
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()));
}
}
}